开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
LeetCode15:三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
示例 1:
输入: nums = [-1,0,1,2,-1,-4]
输出: [[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入: nums = [0,1,1]
输出: []
解释: 唯一可能的三元组和不为 0 。
示例 3:
输入: nums = [0,0,0]
输出: [[0,0,0]]
解释: 唯一可能的三元组和为 0 。
提示:
3 <= nums.length <= 3000
思路分析
题中目的是要找元素的组合,没有要求原始顺序,因此可以排序,若数组是有序的,查找的效率就有提升。
寻找三元素之和为0,固定一个数[i],则变成了在余下的元素中寻找和为 -[i] 的组合。
有序数组,所以可以用双指针来获取目标组合。Left指针从头开始,right从尾开始,碰上时则结束寻找,或者找到结果后就停止。移动的条件是[i]+[j]小于目标时,向右移动左指针,大于目标时向左移动右指针,如果相等,则找到了一对解。
另外不能有重复的,去重逻辑就是,每找到一组元素就向后跨过相同元素。从头向尾遍历的,同一个元素找到的结果 肯定是相同,所以可以直接跨过相同元素。
算法代码
public List < List < Integer >> threeSum(int[] nums) {
Arrays.sort(nums);
int i = 0;
List < List < Integer >> result = new ArrayList < > ();
while (i < nums.length) {
twoSum(nums, i, result);
int temp = nums[i++];
while (i < nums.length && temp == nums[i]) {
i++;
}
}
return result;
}
private void twoSum(int[] nums, int i, List < List < Integer >> result) {
int j = i + 1;
int k = nums.length - 1;
while (j < k) {
if (nums[i] + nums[j] + nums[k] == 0) {
result.add(Arrays.asList(nums[i], nums[j], nums[k]));
int temp = nums[j++];
while (j < nums.length && temp == nums[j]) {
j++;
}
} else if (nums[i] + nums[j] + nums[k] < 0) {
j++;
} else {
k--;
}
}
}
算法复杂度
- 时间复杂度:
- 空间复杂度:
在掘金(JUEJIN)一起进步,一起成长!