題目鏈接:三數之和
題目描述:給你一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例:
給定數組 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合爲:
[
[-1, 0, 1],
[-1, -1, 2]
]
題目分析:關鍵在於不重複,那麼爲了不重複,可以先對數組排序,同時在遍歷過程中控制循環下標和相鄰元素是否相等的判斷,達到去重的目的。繼續說,由於三數之和是固定的,那麼我們在知道其中兩個數之後,第三個數是確定的,所以我們可以固定一個數,然後枚舉另外兩個數。另外兩個數和是確定的,只要其中一個增大,另外一個必定減少,因此,可以採用雙指針進行雙向並行遍歷,減少時間複雜度。
對於本題「雙指針」,當我們需要枚舉數組中的兩個元素時,如果我們發現隨着第一個元素的遞增,第二個元素是遞減的,那麼就可以使用雙指針的方法,將枚舉的時間複雜度從 O(N2)減少至O(N)。爲什麼是 O(N) 呢?這是因爲在枚舉的過程每一步中,「左指針」會向右移動一個位置(也就是題目中的 b),而「右指針」會向左移動若干個位置,這個與數組的元素有關,但我們知道它一共會移動的位置數爲O(N),均攤下來,每次也向左移動一個位置,因此時間複雜度爲 O(N)。
代碼:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int i = 0,l ,r,sum;
while(i < nums.length-2&&nums[i]<=0){
l = i+1;
r = nums.length-1;
while(l<r){
sum = nums[l]+nums[i]+nums[r];
if(sum==0){
res.add(Arrays.asList(nums[l++],nums[i],nums[r--]));
//去重
while(l<r&&nums[l]==nums[l-1]) l++;
while(l<r&&nums[r]==nums[r+1]) r--;
}else if(sum<0){
l++;
}else
r--;
}
i++;
//去重
while(i<nums.length-2&&nums[i]==nums[i-1]) i++;
}
return res;
}
}