Loading

15&16-三数之和问题

三数之和问题是经典型两数之和的问题的升级版,用常规思路来看,两数之和需要O(n2),三数之和需要O(n3)。

显然有复杂度更简单的方法:排序+双指针。

对排序好的数组,我们将有序的三个数最左边(A)就是最小的放在一边,然后将中间的数(B)和最右边的数(C)分别用指针指向,显然B最小从A的下一位数开始,C最大从数组末尾最大的数开始,分别计算三个数的sum:

1、如果大于0,说明C的值偏大,向左以为让C小点,

2、反之小于0,B就向右一位

3、三数之和等于0,返回结果。

如果没有结果,就把A向右挪一位,换个数,重新执行上述循环,尝试ABC其他的组合,寻求正确结果,A 在数组中有nums.size()-1次尝试,故有nums.size()-1次循环。这里面需要注意的一个问题是,ABC三数之和为0,其中A的值必然是小于等于0的,如果A大于0,A是最小值,三数之和必不存在;A=0,唯一存在的可能就是三数都为0,所以执行算法的时候加上这一判断可以减少很多无必要的循环。这也是需要对数组有序排列的一个原因。

这里面还要注意的一个问题是,返回不重复的组合,举例如下{-1,-1,0,1,}。如果执行上述算法思路,会得到{-1,0,1}{-1,0,1}两个结果,因为-1在数组中出现了两次,每次都对应了这种可能,所以我们还要删除存在的重复值。

这里面其中一个思路是用到哈希表不让重复的元素进来。

另一个思路是对A执行下一位的时候进行判断,如果A和之前的A值是一样的话(就如同上述例子中A执行到-1.下一个还是-1)此时就会遇到相同的结果,我们直接进行下一次循环(将A指向0),便可排除重复的数组。

 

这个题仔细想想需要很多的细节实现,不是一点点就可以搞定的,所以我们在做的时候要注意很多细节,包括对数组的有序处理方式,需要多做题多谢代码感受一下。

 1 class Solution {
 2 public:
 3     vector<vector<int>> threeSum(vector<int>& nums) {
 4         int target;
 5         vector<vector<int>> ans;
 6         sort(nums.begin(), nums.end());
 7         for (int i = 0; i < nums.size(); i++) {
 8             if (i > 0 && nums[i] == nums[i - 1]) continue;
 9             if ((target = nums[i]) > 0) break;
10             int l = i + 1, r = nums.size() - 1;
11             while (l < r) {
12                 if (nums[l] + nums[r] + target < 0) ++l;
13                 else if (nums[l] + nums[r] + target > 0) --r;
14                 else {
15                     ans.push_back({target, nums[l], nums[r]});
16                     ++l, --r;
17                     while (l < r && nums[l] == nums[l - 1]) ++l;
18                     while (l < r && nums[r] == nums[r + 1]) --r;
19                 }
20             }
21         }
22         return ans; 
23     }
24 };
View Code

 

posted @ 2020-03-08 09:33  是凉城吖  阅读(322)  评论(0编辑  收藏  举报