力扣(LeetCode)试题--最接近的三数之和 c++实现

3Sum Closest(最接近的三数之和)

Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

示例:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

算法1:暴力求解

将所有可能的三个数的组合穷举出来,然后依次计算与target最接近的和

int diff(const int& v1,const int&v2) {
    int re = v1 - v2;
    return re > 0 ? re : -re;
}

int threeSumClosest1(vector<int>& nums, int target) {
    int sum = 0;
    int sum_temp;
    int diff_min = INT16_MAX;
    vector<int>::iterator begin = nums.begin();
    vector<int>::iterator end = nums.end();

    for (vector<int>::iterator i=begin; i != end - 2; i++) {
        for (vector<int>::iterator j = i + 1; j != end - 1; j++) {
            for (vector<int>::iterator k = j + 1; k != end; k++) {
                sum_temp = *i + *j + *k;
                int dif_temp = this->diff(sum_temp, target);
                if (dif_temp==0)
                {
                    return sum_temp;
                }
                if (dif_temp<diff_min)
                {
                    diff_min = dif_temp;
                    sum = sum_temp;
                }
            }
        }
    }
    return sum;
}

算法优化

先对数据按照升序排序,假设在一次循环中,得到的三个数之和与target的差>0,则最内层循环没有必要继续进行,因为继续循环下去后面的三个数之和与target差值都会大于当前的差值

int diff(const int& v1,const int&v2) {
    int re = v1 - v2;
    //return re > 0 ? re : -re;
    return re;
}
int threeSumClosest2(vector<int>& nums, int target) {
    int sum = 0;
    int sum_temp;
    int diff_min = INT16_MAX;
    vector<int>::iterator begin = nums.begin();
    vector<int>::iterator end = nums.end();
    sort(begin, end);

    for (vector<int>::iterator i = begin; i != end - 2; i++) {
        for (vector<int>::iterator j = i + 1; j != end - 1; j++) {
            for (vector<int>::iterator k = j + 1; k != end; k++) {
                sum_temp = *i + *j + *k;
                int dif_temp = this->diff(sum_temp, target);
                if (dif_temp==0)
                {
                    return sum_temp;
                }

                if (abs(dif_temp) < abs(diff_min))
                {
                    diff_min = dif_temp;
                    sum = sum_temp;
                }

                if (diff_min>0 && dif_temp>diff_min)
                {
                    break;
                }

            }
        }
    }

    return sum;

}

使用暴力求解的算法时间复杂度为O(n3)O(n^3)

算法2:双指针

为了减少算法的时间复杂度,可以考虑使用双指针,将算法的三层循环编程双层循环

先对数组升序排序

设三个数的指针分别为i.j,ki.j,k

  • 固定i=v[0]i=v[0],考虑其他两个数的位置
  • j=i+1,k=nj=i+1,k=n
  • 判断当前的三个数之和sumsum
    • sum<target j++ : 即如果三数之和比target小,则差异更小的数只可能在[j+1,k]之间产生
    • sum>target k– :即如果三数之和比target大,则差异更小的数只可能在[j,k-1]之间产生
  • 记录每次组合的三数之和,更新当前最小和

这样,当一个数固定下来之后,另外两个数的可能产生差异最小的组合通过扫描一次数组就可以完成,即线性时间复杂度,对第一个数枚举,整个算法的复杂度为O(n2)O(n^2)

在这里插入图片描述

int diff(const int& v1,const int&v2) {
    int re = v1 - v2;
    //return re > 0 ? re : -re;
    return re;
}

int threeSumClosest3(vector<int>& nums, int target) {
    int sum = 0;
    int sum_temp;
    int diff_temp;
    int diff_min = INT16_MAX;
    vector<int>::iterator begin = nums.begin();
    vector<int>::iterator end = nums.end();
    sort(begin, end);

    for (vector<int>::iterator i = begin; i != end - 2; i++) {
        vector<int>::iterator j = i + 1;
        vector<int>::iterator k = end - 1;
        while (j!=k)
        {
            sum_temp = *i + *j + *k;
            diff_temp = diff(sum_temp, target);


            if (diff_temp == 0)
            {
                return sum_temp;
            }

            if (abs(diff_temp)<abs(diff_min))
            {
                diff_min = diff_temp;
                sum = sum_temp;
            }

            if (diff_temp < 0)
            {
                j++;
            }
            else {
                k--;
            }
        }



    }
    return sum;
}

算法性能对比

算法 时间 内存
暴力求解 1896ms 9.9MB
双指针 16ms 10.3MB
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章