力扣 15題 : 三數之和
給你一個整數數組 nums ,判斷是否存在三元組 [nums[i], nums[j], nums[k]] 滿足 i != j、i != k 且 j != k ,同時還滿足 nums[i] + nums[j] + nums[k] == 0 。請
你返回所有和為 0 且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例 1:
輸入:nums = [-1,0,1,2,-1,-4]
輸出:[[-1,-1,2],[-1,0,1]]
解釋:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元組是 [-1,0,1] 和 [-1,-1,2] 。
注意,輸出的順序和三元組的順序並不重要。
示例 2:
輸入:nums = [0,1,1]
輸出:[]
解釋:唯一可能的三元組和不為 0 。
示例 3:
輸入:nums = [0,0,0]
輸出:[[0,0,0]]
解釋:唯一可能的三元組和為 0 。
來源:力扣(LeetCode)
鏈接:https://leetcode.cn/problems/3sum
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
解法1 ,使用哈希表映射
參考:算法 - 哈希表 - 兩數之和 與 四數之和
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> listList = new ArrayList<>();
//Set是為了去除重複的list子集
Set<List<Integer>> s = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
int a = nums[i];
Set<List<Integer>> sub = find2Pare(nums, i, 0 - a);
s.addAll(sub);
}
listList.addAll(s);
return listList;
}
/**
把問題化解為兩數之和
*/
Set<List<Integer>> find2Pare(int[] nums, int start, int target){
Set<List<Integer>> lls = new HashSet<>();
Map<Integer, Integer> map = new HashMap<>();
for (int i = start+1; i < nums.length; i++) {
List<Integer> list = new ArrayList<>();
if (map.get(target-nums[i]) != null) {
list.add(nums[start]);
list.add(nums[i]);
list.add(target-nums[i]);
Collections.sort(list);
lls.add(list);
}
map.put(nums[i],i);
}
return lls;
}
}
解法2 雙指針法
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 先做排序
Arrays.sort(nums);
List<List<Integer>> lls = new ArrayList<>();
for(int i = 0 ; i < nums.length-2; i++) {
// 如果當前數值大於0 ,因為是有序數組,後面的數值都是不可能和為0的,直接返回
if(nums[i] > 0){
return lls;
}
//對第一個數值去重
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
int a = nums[i];
int left = i+1;
int right = nums.length-1;
while(left < right){
if(a + nums[left] + nums[right] == 0){
List<Integer> list = new ArrayList<>();
list.add(a);
list.add(nums[left]);
list.add(nums[right]);
lls.add(list);
// 去重在找到第一個元素之後執行
// 對right指針元素去重
while(left < right && nums[right] == nums[right-1]){
right--;
}
// 對left指針元素去重
while(left < right && nums[left]== nums[left+1]){
left++;
}
// 找到答案後,雙指針收縮
left++;
right--;
}
else if(a + nums[left] + nums[right] > 0){
right--;
}else {
left++;
}
}
}
return lls;
}
}