Description
给出一个有n个整数的数组S,在S中找到三个整数a, b, c,找到所有使得a + b + c = 0的三元组。
注意事项
在三元组(a, b, c),要求a <= b <= c。
结果不能包含重复的三元组。
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0
? Find all unique triplets in the array which gives the sum of zero.
Notice
Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4}
, A solution set is:
(-1, 0, 1)
(-1, -1, 2)
Solution
解题思路:将Three-Sum的问题转换为Two-Sum的问题
1. 上来先排序
2. 将a + b + c = 0 Three-Sum的问题转换为 -a = b + c Two-Sum的问题
3. 循环小的那个数a(如果重复就跳过),并在剩下的区间里寻找和为-a的target,这道题中剩下的区间就是i + 1到nums.length - 1;
注意:
1. 排序。这种题上来先看是否有序,无序的话要先排序。
2. 去除重复。通过比较前后是否相等的方式来去除重复,如果前后相同,则指针继续跳,直到找到不同元素为止。
public class Solution {
/**
* @param numbers: Give an array numbers of n integer
* @return: Find all unique triplets in the array which gives the sum of zero.
*/
public List<List<Integer>> threeSum(int[] numbers) {
// write your code here
//1. 上来先排序
//2. 将a + b + c = 0 3-Sum的问题转换为 -a = b + c Two-Sum的问题
//3. 循环小的那个数a(如果重复就跳过)在剩下的区间里寻找和为-a的target
List<List<Integer>> results = new ArrayList<>();
if (numbers == null || numbers.length < 3) {
return results;
}
Arrays.sort(numbers);
for (int i = 0; i < numbers.length - 2; i++) {
// skip duplicate triples with the same first numebr
//从第二个数开始检测,如果nums与前一个数相同则直接跳过,避免重复
if (i > 0 && numbers[i] == numbers[i - 1]) {
continue;
}
int left = i + 1, right = numbers.length - 1;
int target = -numbers[i];
twoSum(numbers, left, right, target, results);
}
return results;
}
private void twoSum(int[] nums,
int left,
int right,
int target,
List<List<Integer>> results) {
while (left < right) {
if (nums[left] + nums[right] == target) {
//添加这种组合到results中
ArrayList<Integer> triple = new ArrayList<>();
triple.add(-target);
triple.add(nums[left]);
triple.add(nums[right]);
results.add(triple);
left++;
right--;
//跳过重复元素
while (left < right && nums[left] == nums[left - 1]) {
left++;
}
while (left < right && nums[right] == nums[right + 1]) {
right--;
}
} else if (nums[left] + nums[right] < target) {
left++;
} else {
right--;
}
}
}
}