LeetCode——三数之和

Posted 霜序之晦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode——三数之和相关的知识,希望对你有一定的参考价值。

题目:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:

输入:nums = []
输出:[]
示例 3:

输入:nums = [0]
输出:[]

提示:

  • 0 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

分析:因为最终要得到的和为0,所以可分为两种情况,一种是正数负数相加从而和为0,另一种是三个0相加和为0,而正数负数相加又分三种:一个负数、一个正数、一个零,两个负数、一个正数,一个负数、两个正数。

思路:根据以上分析,可以先对数组排序,通过两个指针将将整个数组分为三个部分,负数、0、正数,第一个指针指向第一个非负数,第二个指针指向第一个大于0的数。注意:此处第一个指针和第二个指针可能指向同一个位置,也即数组中不含有0的情况。

双指针

 

处理重复结果:因为数组已经排序,所以在迭代循环时可以很方便地跳过相同的值,如此可以保证每种结果只出现一次。

关于迭代循环,例如一个负数和两个正数的情况:用一个指针用来指示负数,另外两个指针分别指向正数中最大值,最小值,通过把他们的值相加与负数乘-1作比较,因为数组有序,所以如果正数和更小的话,就将指示最小值的指针右移,反之则左移最大值指针,如果值相等则将这三个数作为结果保存,同时分别移动前后两个正数指针。当一轮迭代完成(两个正数指针相遇),就将指示负值的指针右移,继续新一轮迭代。当负数指针抵达非负数这一边界即表明迭代完成,至此两个正数一个负数的情况便处理完毕,其余情况都与之类似,因此不做赘述。

代码如下:

 1 vector<vector<int>> threeSum(vector<int>& nums) {
 2     int size = nums.size();
 3     vector<vector<int>>ret;
 4     if (size < 3)return ret;
 5     sort(nums.begin(), nums.end());
 6     auto iterFirst0 = find_if(nums.begin(), nums.end(), [](const int& v) {return v >= 0; });
 7     auto iterFirstGt0 = find_if(nums.begin(), nums.end(), [](const int& v) {return v > 0; });
 8     //存在3个0
 9     if (iterFirstGt0 - iterFirst0 >= 3)ret.push_back({ 0,0,0 });
10     //左边1个右边两个
11     auto iterN = nums.begin();
12     int lastValue = *iterN;
13     while (iterN != iterFirst0)
14     {
15         for (auto iter1 = iterFirstGt0, iter2 = nums.end() - 1; iter1 < iter2;)
16         {
17             if ((*iter1) + (*iter2) < -1 * lastValue) ++iter1;
18             else if ((*iter1) + (*iter2) > -1 * lastValue)--iter2;
19             else
20             {
21                 int v1 = *iter1, v2 = *iter2;
22                 ret.push_back({ lastValue,v1,v2 });
23                 while (iter1 < iter2 && v1 == *iter1)++iter1;
24                 while (iter1 < iter2 && v2 == *iter2)--iter2;
25             }
26         }
27         while (iterN < iterFirst0 && lastValue == *iterN)++iterN;
28         lastValue = *iterN;
29     }
30     //左边两个右边一个
31     vector<int>::iterator iterP = iterFirstGt0;
32     auto iterLast0 = iterFirstGt0 - 1;
33     lastValue = *iterP;
34     while (iterP != nums.end())
35     {
36         for (auto iter1 = nums.begin(), iter2 = iterFirst0 - 1; iter1 < iter2;)
37         {
38             if ((*iter1) + (*iter2) < -1 * lastValue)++iter1;
39             else if ((*iter1) + (*iter2) > -1 * lastValue)--iter2;
40             else
41             {
42                 int v1 = *iter1, v2 = *iter2;
43                 ret.push_back({ v1,v2,lastValue });
44                 while (iter1 < iter2 && v1 == *iter1)++iter1;
45                 while (iter1 < iter2 && v2 == *iter2)--iter2;
46             }
47         }
48         while (iterP < nums.end() && lastValue == *iterP)++iterP;
49         if (iterP != nums.end())lastValue = *iterP;
50     }
51     //左边一个右边一个
52     if (*iterFirst0 == 0)
53     {
54         iterN = nums.begin();
55         iterP = nums.end() - 1;
56         while (iterN < iterFirst0 && iterP >= iterFirstGt0)
57         {
58             if (*iterN + *iterP < 0)++iterN;
59             else if (*iterN + *iterP > 0)--iterP;
60             else
61             {
62                 int v1 = *iterN;
63                 int v2 = *iterP;
64                 ret.push_back({ v1,0,v2 });
65                 while (iterN < iterFirst0 && v1 == *iterN)++iterN;
66                 while (iterP >= iterFirstGt0 && v2 == *iterP)--iterP;
67             }
68         }
69     }
70     return ret;
71 }

三数之和

以上是关于LeetCode——三数之和的主要内容,如果未能解决你的问题,请参考以下文章

leetcode-----16. 最接近的三数之和

LeetCode Hot 100 --- 三数之和 (java详解)

LeetCode5.三数之和(C++,Python)

LeetCode 16最接近的三数之和

[leetcode 16] 最接近的三数之和

LeetCode 16. 最接近的三数之和