一、Problem
Given an array nums of n integers, are there elements a, b, c in nums 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.
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
二、Solution
嘗試一:雙指針
生套滑窗是不行的,因爲窗口中的數字有可能被重用。
class Solution {
public List<List<Integer>> threeSum(int[] a) {
Set<List<Integer>> st = new HashSet<>();
int n = a.length, l = 0, r = 0, sum = 0;
LinkedList<Integer> cur = new LinkedList<>();
while (r < n) {
sum += a[r];
cur.add(a[r]);
r++;
while (sum == 0) {
st.add(new ArrayList(cur));
sum -= a[l];
l++;
cur.pollFirst();
}
}
List<List<Integer>> ans = new LinkedList<>();
for (List<Integer> b : st) {
ans.add(b);
}
return ans;
}
}
這題沒有對答案的數字數字要求爲按照 nums 中的數字順序,所以可以用排序來簡化去重操作。
方法二:排序 + 二分思想
- 選定一個頂點 ,再選定一個需要枚舉的區間
- 在區間中,我們需要考慮:
- 三數之和 sum 的值:大於 0、小於 0、等於 0
- 等於 0:如果當前窗口的兩端的相鄰元素是相同的,那麼這些元素構成的子集會產生重複,所以這些重複數不可要。
- 大於 0:要讓 sum 變小,只能讓 向左移動。
- 小於 0:要讓 sum 變大,只能讓 向右移動。
- 三數之和 sum 的值:大於 0、小於 0、等於 0
class Solution {
public List<List<Integer>> threeSum(int[] a) {
Arrays.sort(a);
List<List<Integer>> ans = new LinkedList<>();
int n = a.length;
for (int i = 0; i < n; i++) {
if (a[i] > 0)
break;
if (i > 0 && a[i-1] == a[i])
continue;
int l = i + 1, r = n - 1;
while (l < r) {
int sum = a[i] + a[l] + a[r];
if (sum == 0) {
ans.add(Arrays.asList(a[i], a[l], a[r]));
while (l < r && a[l] == a[l+1]) l++;
while (l < r && a[r] == a[r-1]) r--;
l++; r--;
}else if (sum < 0) l++;
else r--;
}
}
return ans;
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,