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——三数之和的主要内容,如果未能解决你的问题,请参考以下文章