【3Sum Closest 】cpp
题目:
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
For example, given array S = {-1 2 1 -4}, and target = 1. The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
代码:
class Solution { public: int threeSumClosest(vector<int> &num, int target) { // sort the num std::sort(num.begin(), num.end()); // return value & min_gap int closest_sum = 0; int min_gap = INT_MAX; // from two sides to mid for (std::vector<int>::iterator i=num.begin(); i!=num.end()-2; ++i) { std::vector<int>::iterator j = i+1; std::vector<int>::iterator k = num.end()-1; while(j<k) { const int sum = *i+*j+*k; const int gap = std::abs(target-sum); if (gap < min_gap) { closest_sum = sum; min_gap = gap; } // move according to the sum and target if (sum<target) { ++j; } else if (sum>target) { --k; } else { return target; } } } return closest_sum; } };
Tips:
1. 方法就是:“先排序,再夹逼”这是一种时间复杂度为O(n²),空间复杂度为O(1)的常用技巧
2. 方法的实现技巧是设置头尾两个pointer,根据sum与target的关系大小选择指针move的方向
3. 为什么要先排序再夹逼?因为可以根据sum与target关系调整大小,使其每次计算都能有目标地移动。这样每次遍历保证能得到包含*i在内的最优sum。
==================================================
第二次过这道题,有了3Sum的基础之后,这道题的思路也就有了。
class Solution { public: int threeSumClosest(vector<int>& nums, int target) { int ret = 0; if (nums.size()<3 ) { for ( int i=0; i<nums.size(); ++i ) ret += nums[i]; return ret; } ret = nums[0]+nums[1]+nums[nums.size()-1]; std::sort(nums.begin(), nums.end()); for ( int i=0; i<nums.size()-2; ++i ) { if ( i>0 && nums[i]==nums[i-1] ) continue; int begin = i+1; int end = nums.size()-1; while ( begin<end ) { int value = nums[i]+nums[begin]+nums[end]; if ( value<target ) { ret = abs(ret-target)>abs(value-target) ? value : ret; begin++; while ( begin<end && nums[begin-1]==nums[begin] ) begin++; } else if ( value>target ) { ret = abs(ret-target)>abs(value-target) ? value : ret; end--; while ( begin<end && nums[end]==nums[end+1] ) end--; } else { return target; } } } return ret; } };
tips:
大体思路还是“排序+双指针夹逼”
具体的做法就是每次算一个可能的更贴近结果的和后,就检查一次要更新返回的值。
上述的代码有些麻烦了。
如果不直接维护返回值,而是维护一个与target的差值,这样就省去了很多麻烦。而这种简便一些的思路是第一次学习别人代码AC的思路。