三数之和问题
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
问题分析
如果只寻找满足条件的三元组其实是很容易的,我们可以分步操作,先计算两数之和,在判断是否有第三个数加上满足和为零,记录满足条件的三元组,但是这样会产生很多重复的三元组,所以需要对三元组进行去重,一般的方法处理会显得非常繁杂,不好操作。
这里使用双指针是比较容易操作的
基本操作流程为:
- 先给数组以升序排好序
- 外层一个for循环遍历数组,i对应其下标
- 循环内部定义两个指针left=i+1,right=nums.length-1,其中a=nums[i],b=nums[left],c=nums[right]
- 通过移动两个指针找到当前a=nums[i]时,所有满足条件的三元组
- 移动方式为:当nums[i] + nums[left] + nums[right] > 0时,说明三数之和大了,right左移
当nums[i] + nums[left] + nums[right] < 0时,说明三数之和小了,left右移
去重操作
- a: 判断当前元素是否与上一个元素大小相同,是则跳过当前元素
if (i > 0 && nums[i - 1] == nums[i]) { continue; }
- b:判断下一个元素是否与当前元素大小相同,是则跳过下一个元素
while (left < right && nums[left] == nums[left+1]) left++;
- c:判断下一个元素是否与当前元素大小相同,是则跳过下一个元素
while (left < right && nums[right] == nums[right-1]) right--;
代码
public List<List<Integer>> threeSum(int[] nums) {
//存储三元组的数组
List<List<Integer>> result = new ArrayList<>();
//对数组进行排序
Arrays.sort(nums);
for(int i=0;i<nums.length;i++) {
//因为是排好序,从小到大,如果a大于零,表示不存在满足条件的三元组
if (nums[i] > 0) {
return result;
}
//对a做去重操作
if (i > 0 && nums[i - 1] == nums[i]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
if (nums[i] + nums[left] + nums[right] > 0) {
//和大于零,右边指针向左移动,即c值大小减小
right--;
} else if ( nums[i] + nums[left] + nums[right] < 0) {
//和小于零,左边指针向右移动,即b值大小增大
left++;
} else {
//和等于零,保存结果
List<Integer> ok = new ArrayList<>();
ok.add(nums[i]);
ok.add(nums[left]);
ok.add(nums[right]);
result.add(ok);
//对b,c做去重处理
while (left < right && nums[right] == nums[right-1]) right--;
while (left < right && nums[left] == nums[left+1]) left++;
//找到一个结果后,两指针同时移动到下一个位置
right--;
left++;
}
}
}
return result;
}