您的位置:首页 > 编程语言 > C语言/C++

Leetcode: 15. 3Sum(Week3,Medium)

2017-09-24 17:48 567 查看
注:本题算法无需实现去重操作。

Leetcode 15

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:

[

[-1, 0, 1],

[-1, -1, 2]

]

题意:

现有一个数组S,题目希望你实现一个算法,能够找出该数组中满足a+b+c = 0的所有a、b、c组合,并且不能有重复的情况。

思路

首先说一下常规思路:先求出所有的情况,然后再进行去重。

对于求解所有情况,可以采用暴力解法,但开销有点大;也可以采用排序的方式,开销比较小,这个待会会解释。

对于去重,很容易就想到用STL中的set容器。但是有个问题,set容器可以检测出[1,2,3]与[1,2,3]是相同的,但是无法得到出[3,2,1]与[1,2,3]也是相同的情况,应该去除。不过也可以考虑将[3,2,1]与[1,2,3]加入一个set中,如果set的大小为3,说明[3,2,1]与[1,2,3]只需要一个。不过还是好麻烦好麻烦~

所以讲一下我的思路:在查找的时候避开重复的情况,这样最终得到的vector是不会包含重复的结果的。

首先,需要对数组进行排序。为什么进行排序?有三点原因:第一,观察题目给出的example,可以发现每种情况都是有序的;第二,通过排序,可以减少循环的次数;第三,通过排序,为避开重复的情况奠定了基础。

然后,定义第一层循环,遍历数组元素。这层循环中遍历的数组元素,可以作为a,于是就能得出b+c = -a。定义front与back变量,使用一个while循环,从两边向中间遍历,找到符合条件的组合,加入到vector中。当b+c>-a, 说明和太大了,需要减少,所以将back–;当b+c< -a,说明和太小了,需要增大,所以front++; 当b+c = -a时,满足条件,加入vector,并进行一个或多个front++与back–,找到与之前不同的s[front]与s[back]。当然,这样只是避开了b、c的重复情况,对于a也要做相应处理。即在while循环外进行i++,直到s[i+1]!=s[i]。

算法:在思路中已经较为详细的阐述,如果还是有点抽象,可以参考下面代码及注释。

代码如下:

/*
2017/9/24  3Sum(a+b+c=0)
主要思路:
1. 将数组排序(减少循环次数;避免重复情况;结果是有序的);
2. 第一层循环遍历vector数组,数组元素代表a;
3. 定义两个变量front与back,一个从第一层循环的数组元素的下一个开始,一个从数组的最后一个开始。
用一个while循环实现front与back向中间移动,查找两个元素的和为第一个数组元素的相反数;
4. 避开了重复的情况。因为数组排序了,在遍历的过程中可以跳过相同的元素。
*/
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int> > res;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
int target = -nums[i];
int front = i+1;
int back = nums.size()-1;
while(front < back) {
// 说明和过大,需要减少
if (nums[front] + nums[back] > target) {
back--;
// 说明和过小,需要增大
} else if (nums[front] + nums[back] < target) {
front++;
// 和满足的情况下
} else {
vector<int> item;
vector<int> temp(3, 0);
temp[0] = nums[i];
temp[1] = nums[front];
temp[2] = nums[back];
item.push_back(nums[i]);
item.push_back(nums[front]);
item.push_back(nums[back]);
res.push_back(item);
// 找到与之前不同的b、c
while(front < back && nums[front] == temp[1]) front++;
while(front < back && nums[back] == temp[2]) back--;
}
}
// 找到与之前不同的a
// 此处使用i+1是因为for循环的循环更新变量(i)会在本次循环结束的时候递增
while(i+1 < nums.size() && nums[i+1] == nums[i]) i++;
}
return res;
}
};


以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息