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]。
算法:在思路中已经较为详细的阐述,如果还是有点抽象,可以参考下面代码及注释。
代码如下:
以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!
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; } };
以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!
相关文章推荐
- Leetcode: 73. Set Matrix Zeroes(Week15, Medium)
- Leetcode 15 [medium]--3Sum
- LeetCode-15-3Sum(证明/KSum)-Medium
- 【leetcode】3Sum (medium)
- 【一天一道LeetCode】#15 3Sum
- leetcode 15:3Sum
- leetcode——15——3Sum
- 3Sum - LeetCode 15
- leetcode-15-3sum
- LeetCode 15 -- 3Sum
- LeetCode 15 3Sum
- LeetCode刷题(C++)——3Sum Closest(Medium)
- Leetcode-15: 3Sum
- LeetCode | 15. 3Sum(三数和为定值)
- LeetCode 15---3Sum
- 【Leetcode】【Medium】3Sum Closest
- [LeetCode] 15. 3Sum
- leetcode-15 3sum
- LeetCode:3Sum_15
- LeetCode 15 3Sum