题目: 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
示例:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
输入:nums = [0]
输出:[]
方法一:官方方法(排序+双指针)
对排序后的结果固定一个数,对剩下的数进行双指针找符合条件的两个值。
在这个思路上优化。
设固定的数为nums[a],若nums[a] > 0,则三数之和一定大于零,不符合条件结束循环。
当 nums[a] == nums[a - 1] 时,会产生重复的枚举,去重。例如:[1,1,2,3],固定nums[0]和nums[1],对剩下的双指针都会枚举到[1,2,3]这个数组,应该去重去掉。
同样nums[b]也是这样去重。
双指针和大于零,c左移。和小于零,b右移。这都比较容易处理了
public static List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
for (int a = 0; a < n; a++) {
if (nums[a] > 0) {
break;
}
//a和上一位数字一样结束此次循环,右移一位
if (a > 0 && nums[a] == nums[a - 1]) {
continue;
}
int c = n - 1;
//a固定 b、c双指针
for (int b = a + 1; b < n; b++) {
//b和上一位数字一样结束此次循环,右移一位
if (b > a + 1 && nums[b] == nums[b - 1]) {
continue;
}
//和大于零 c左移
while (b < c && nums[a] + nums[b] + nums[c] > 0) {
c--;
}
//bc重合,指针重合
if (b == c) {
break;
}
if (nums[a] + nums[b] + nums[c] == 0) {
ArrayList<Integer> list = new ArrayList<>();
list.add(nums[a]);
list.add(nums[b]);
list.add(nums[c]);
ans.add(list);
}
}
}
return ans;
}
方法二:
在官方基础上对nums[c] 也进行了去重处理,双指针用while更容易看和书写。
public static List<List<Integer>> threeSum1(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
for (int a = 0; a < n; a++) {
//a和上一位数字一样结束此次循环,右移一位
if (a > 0 && nums[a] == nums[a - 1]) {
continue;
}
int c = n - 1;
int b = a + 1;
// b、c双指针
while (b < c) {
while (b > a + 1 && nums[b] == nums[b - 1]) {
//不加这个条件可能会出现 b>=c的情况
if (b < c) {
b++;
continue;
}
}
while (c > n - 1 && nums[c] == nums[c + 1] ) {
if (b < c) {
c--;
continue;
}
}
if (nums[a] + nums[b] + nums[c] == 0) {
ArrayList<Integer> list = new ArrayList<>();
list.add(nums[a]);
list.add(nums[b]);
list.add(nums[c]);
ans.add(list);
//改变两边指针
b++;
c--;
} else if (nums[a] + nums[b] + nums[c] < 0) {
//和小于零,左指针 右移动
b++;
} else {
//和大于零,右指针 左移动
c--;
}
}
}
return ans;
}
总结:
方法都是排序+双指针就是双指针的处理不太一样。
这题不难理解,就是去重需要一些方法