難度中等
給你一個包含 n 個整數的陣列
nums
,判斷nums
中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例:
給定陣列 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合為:
[[-1, 0, 1],[-1, -1, 2]]
在看這個問題之前可以先看下 兩數之和
當碰到這個三數之和的時候,首先想到的思路就是既然 a + b = c
,那麼 a + b = -c
,我在想,是不是可以以這個 -c
為 target
,然後迭代陣列,重用這個兩數之和的方法?程式碼如下:
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
HashSet<List<Integer>> set = new HashSet<>();
for(int i = 0;i<nums.length;i++){
List<List<Integer>> res = twoSum(nums,-nums[i],i);
if(res != null && res.size() != 0){
for(List<Integer> l : res) {
//將適合的數對與當前陣列合起來然後去重!!!
int[] arr = new int[]{nums[i], l.get(0), l.get(1)};
Arrays.sort(arr); //通過排序進行去重!!!
List<Integer> list1 = new ArrayList<>();
list1.add(arr[0]);
list1.add(arr[1]);
list1.add(arr[2]);
if (!set.contains(list1)) {
set.add(list1);
}
}
}
}
List list2 = new ArrayList(set);
System.out.println(list2.toString());
return list2;
}
public List<List<Integer>> twoSum(int[] nums, int target ,int j){
//兩數之和,返回所有和為目標和的數對!!!注意 傳入的本位 j 應該跳過!!!
HashSet<Integer> hashSet = new HashSet<>();
List<List<Integer>> list = new ArrayList<>();
for(int i = 0;i<nums.length;i++){
if(i == j){
continue;
}
if(hashSet.contains(target - nums[i])){
List<Integer> l = new ArrayList<>();
l.add(nums[i]);
l.add(target - nums[i]);
list.add(new ArrayList<>(l));
}
hashSet.add(nums[i]);
}
return list;
}
結果
超時了。。。。。。。找出合適的數對的時間複雜度就 O(n ^ 2),然後又通過排序進行去重,整體的時間複雜度固然很高
排序加雙指標
首先因為所求為三個數之和為0,不需要求下標,所以可以對陣列進行排序,使得整體具有規律性!其實兩數之和也可以通過排序加雙指標,但是那個題所求為下標,不能打亂陣列,所以最好的就是用雜湊表。一旦排好序之後,就可以用上面的思路了,即將每個數作為 target
,然後遍歷剩下的數,進行判斷!
其實這裡邊有很多技巧,可以仔細通過程式碼體會:
public List<List<Integer>> threeSum1(int[] nums) {
if(nums == null || nums.length <= 2){
return new ArrayList<>();
}
List<List<Integer>> res_list = new ArrayList<>();
int len = nums.length;
int left = -1;
int right = -1;
Arrays.sort(nums); //排序是前提!!!使其有序之後,才可以通過一些條件加速過程
for(int i = 0;i < len;i++){
if(nums[i] > 0){
//如果當前位置大於零,說明之後的都大於零,一定不可能湊出三個數使得 a + b + c = 0!
break;
}
if(i >= 1 && nums[i] == nums[i -1]){
//如果當前數字等於前一個數字,說明是重複的,沒必要在進行之後判斷!
continue;
}
left = i + 1; //從後面一個數字開始即可!
right = len - 1;
while(left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
res_list.add(list);
left++;
right--;
//以下兩個while迴圈為去重過程
while (left < right &&nums[left] == nums[left - 1]) {
left++;
}
while(left < right && nums[right] == nums[right + 1]){
right --;
}
}else if(sum > 0){
right --;
}else{
left ++;
}
}
}
return res_list;
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結