LeetCode第15题-三数之和-java实现-图解思路与手撕代码
一、题目描述
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
二、解题思路与代码实现
1.解题思路
这道题的想法是遍历数组,固定遍历的数字,在剩余数组中的头和尾移动两个指针,当三数之和大于0时移动右指针,反之移动左指针。
当然前提是对数组进行排序。
问题难点在于如何移动指针,以保证得到的结果没有重复的数字组合。
结局这个难点就要思考如何在有序数组中得到不重复的数字组合,对于遍历数组的指针和头尾两个指针,移动时应该跳过相同的数字,避免得到相同的结果。
2.相加部分实现
代码如下(示例):
首先对数组进行排序,这里采用快速排序,或者也可以使用Arrays提供的sort函数。
其次检查数组的首尾元素,如果最小的大于0,最大的小于0,都说明没有三个数之和等于0,直接返回空列表就可以了。
然后进行遍历,取首尾两个指针,判断是否加和为0,如果是,就加入到结果列表中。
最后移动遍历指针和首尾两个指针,跳过相同元素,重复进行判断,直到遍历结束为止。
private static List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new LinkedList<>();
nums = quickSort(nums);
if (nums[0] > 0 | nums[nums.length - 1] < 0) {
return res;
}
int i = 0;
while (i < nums.length - 2) {
if (nums[i] > 0) {
break;
} else {
int j = i + 1, k = nums.length - 1;
while (j < k) {
if (nums[i] + nums[j] + nums[k] == 0) {
List<Integer> temp = new LinkedList<>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[k]);
res.add(temp);
while (j < nums.length - 1 && nums[j] == nums[j + 1]) {
j++;
}
j++;
while (k > 0 && nums[k] == nums[k - 1]) {
k--;
}
k--;
} else if (nums[i] + nums[j] + nums[k] > 0) {
k--;
} else {
j++;
}
}
}
while (i < nums.length - 1 && nums[i] == nums[i + 1]) {
i++;
}
i++;
}
return res;
}
快速排序算法如下所示:
private static int[] quickSort(int[] nums) {
for (int i = 0; i < nums.length; i++) {
int minIdx = i;
for (int j = i + 1; j < nums.length; j++) {
if (nums[minIdx] > nums[j]) {
minIdx = j;
}
}
int temp = nums[minIdx];
nums[minIdx] = nums[i];
nums[i] = temp;
}
return nums;
}
总结
这个问题最容易想到暴力求解法,在此基础上进行优化,固定一个数字,然后对剩余数组进行双指针遍历,难点在于如何在保证不遗漏结果的同时快速有效的排除重复组合,在上述回答中已经给出了答案。
|