题目地址(3sum/“>15. 三数之和)
https://leetcode-cn.com/problems/3sum/
题目描述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 给你一个包含 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
|
前置知识
公司
思路
这题的思路是建立在两数之和的基础进行求解的,与两数之和不同的是,这里不再要求返回索引,,因此先进行排序,,然后使用双指针的思路是颗星的。具体的算法是对原数组进行依次排序,然后一层循环固定一个元素,循环内部利用双指针找出剩下的两个元素,这里特别注意需要去重。上述算法出去排序部分的时间复杂度为O(n^2),相比之下排序过程不会成为性能瓶颈。
关键点
- 这里的关键点除了基本的算法思想之外,注意list的定义是每次循环的时候定义的(翻译的python代码就是这样定义得)虽然这样定义会导致空间的浪费,但是鉴于题目要求的特殊性,如果不是每次循环定义,而是使用同一个list会导致越来越多,最后全部集中在一个list中。
代码
Java Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { public List<List<Integer>> threeSum(int[] nums) { int n=nums.length; Arrays.sort(nums); List<List<Integer>> res=new ArrayList();
for(int i=0;i<nums.length-2;i++){ if(i>0&&nums[i]==nums[i-1]) continue; int l=i+1; int r=n-1; while(l<r){ if(nums[i]+nums[l]+nums[r]<0) l+=1; else if(nums[i]+nums[l]+nums[r]>0) r-=1; else{ List<Integer> tmp=new ArrayList(); tmp.add(nums[i]); tmp.add(nums[l]); tmp.add(nums[r]); res.add(tmp); while(l<r && nums[l]==nums[l+1]) {l+=1;} while(l<r && nums[r]==nums[r-1]) {r-=1;} l+=1; r-=1; } } } return res; } }
|
复杂度分析
令 n 为数组长度。
- 时间复杂度:$O(n^2)$
- 空间复杂度:$O(n)$