题目链接
https://leetcode-cn.com/problems/3sum/
题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
解题思路
- 最容易想到的思路就是暴力解法,写个三重循环,把所有的情况都列举一般,但是这种解法一般都会超时,而且题目中还说了不能有重复的三元组,就比如输入的是-1,0,1,-1,0,1。这种在暴力的时候就会出现重复,所以还要想办法去重,所以这种解法一般不可取。
- 题目中提到是是不重复,那我们是不是可以首先进行排序,然后在筛选的时候三个数a,b,c的时候,保证a<=b<=c。这样是不是就少了一些重复的可能性,比如(a,b,c),(b,a,c),(c,b,a)这些就会被筛选掉了
- 当然满足a<=b<=c并不能把所以重复的情况去掉。比如-1,-1,-1,0,0,0,0,1,1,1(排序后)。这样根据上面的条件就无法解决了,下面说一个解决的办法
- 比如我们在选其中a的时候,如果a选-1了,那接下来在遍历的时候,a就不能在选-1.有没有啥好办法呢!办法就是:我们在进行遍历的时候,如果选a的这个数不是数组的第一个元素,那么判断一个这个数和这个数前面的数是否相等,如果相等,直接continue即可,因为a已经选过了。
- 既然三重循环求解会超时,那么我们可以先排序,再进行二重循环。
- 外层循环就是枚举第一个数a,在这个外层循环的里面首先要进行判断a是否重复使用过了(使用上面4的方法),再定义一个变量,用来扫描数组c。
- 然后就开始第二层循环,这个循环是枚举第二个数b,b从a后面的一个数开始枚举(从左到右扫描),同时也要判断b是否重复的问题,解决办法和a一样,在这二层循环里面,再用一个while循环,从右到左扫描c
- 虽然是二层循环里面套while循环,但是他并不是三重循环的时间复杂度。因为假如我们在固定a的情况下,找到了一对b和c满足了情况跟,接再来在枚举b和c的时候,实在上一个找到的情况下进行继续扫描的,如图所示:
代码
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { int len=nums.size(); sort(nums.begin(),nums.end()); vector<vector<int> > ans; //开始枚举 a for(int first=0;first<len;first++) { //需要和上一次枚举的数不相同 if(first>0&&nums[first]==nums[first-1]) continue; int Target=-nums[first]; // c 指向数组的最右端 int third=len-1; //开始枚举b for(int second=first+1;second<len;second++) { //需要和上一次枚举的数不相同 if(second>first+1&&nums[second]==nums[second-1]) continue; //需要保证b在c的左侧 while(second<third&&nums[second]+nums[third]>Target) third--; //如果指针重合,随着b的增长,就不会有满足a+b+c=0了 if(second==third) break; if(nums[second]+nums[third]==Target) ans.push_back({nums[first],nums[second],nums[third]}); } } return ans; } };
扫描二维码关注公众号,回复: 11300760 查看本文章