ps:本文章仅用来记录日常学习的所思所想,各位看到可取之处也可纳为己用,说的不对的地方还请多多指教。
1.题目描述
15.三数之和(中等)
2.题目分析
按照惯例,先理解我们要干什么;
最关键的就是三元组是什么,按照题意,三元组是从给的数组中取出来三个元素来组成一个新数组,而且元组不能重复,那么我们该怎么取三个元素出来,我第一个想到的就是定一个值然后用两个指针来遍历,看代码先吧。
public class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}
return result;
}
}
首先说说为什么要先排序数组
Arrays.sort(nums);
排序后,我们可以固定一个数值(例如,将其作为第一个元素),然后使用双指针在剩余数组中寻找另外两个数,使得它们的和为当前固定数值的相反数。这样,我们可以将三数之和问题转化为两数之和问题。总之,有序总比无序好处理。
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
这个if语句就是避免三元组重复的最关键的地方,当当前起始值等于上一次循环的起始值时,会执行continue 跳出当前循环,执行下一次的循环,这样就避免了起始值的重复,但还不足以避免三元组的重复,三元嘛当然三个元素都要避免。
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}
然后就是我们喜闻乐见的双指针环节,按照国际惯例 我的惯例,都是用一个指针在前,一个在后,然后while(left<right)就是循环到他们相遇,保证不漏循。
Arrays.asList(nums[i], nums[left], nums[right])
这里特别说明一下这个方法, 作用是将里面的三个元素组成一个列表。同时如果传进去的参数是数组的话还有数组转换为列表的作用。
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
这一块就是避免后面两元重复了 ,当各自的值跟上一次循环的值相等时跳过当前值,但如果你问我为什么第一个元跟这后面两元的避免方式不一样,我只能说避免审美疲劳(bushi)。
else if (sum < 0) {
left++;
} else {
right--;
这里的逻辑就是如果当前三个数的和 sum
小于 0,意味着当前的和偏小,又因为数组是排序过的,自然需要增加一些数值以达到 0的话,就是left++,反之自然就是right--
3.总结
双指针问题不要用for循环去限制双指针的发挥