给你一个整数数组 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, -10^5<=nums[i]<=10^5
1、排序+双指针
基本思路:先给数组排序,然后枚举第一个数,后两个数用双指针寻找。详细注释我会写在代码里面
时间O(N2),N为数组长度
空间O(logN),忽略存储答案的空间,额外的排序的空间复杂度为 O(logN)
python:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
# 数组排序
nums.sort()
# ans变量用来存储结果
ans = []
# 如果数组长度小于3,或者排序后第一个数大于0、最后一个数小于0,
# 那么一定找不到这样的三元组,则直接返回空数组
if n < 3 or nums[0] > 0 or nums[n - 1] < 0:
return ans
# 排序后数组第一个数和最后一个数都等于0,说明整个数组都是0,返回固定值
if nums[0] == 0 and nums[n - 1] == 0:
return [[0, 0, 0]]
# 枚举第一个数
for i in range(n-2):
# 如果枚举的数字不是第一个数,且这个数和前面的数重复了,跳出本次循环
if i > 0 and nums[i] == nums[i - 1]:
continue
# 如果枚举的数大于0,跳出本次循环
if nums[i] > 0:
break
# 定义左右指针
left = i + 1
right = n - 1
# 开始查找
while left < right:
sum = nums[i] + nums[left] + nums[right]
# 和为0,则获取一组结果
if sum == 0:
ans.append([nums[i], nums[left], nums[right]])
# 增加左指针,注意要跳过相同的数
while left < right and nums[left] == nums[left+1]:
left += 1
# 缩短右指针,跳过相同数
while left < right and nums[right] == nums[right-1]:
right -= 1
# 不存在重复数字,直接缩短
left += 1
right -= 1
# 否则和大于0,缩短右指针
elif sum > 0:
right -= 1
# 否则增加左指针
else:
left += 1
return ans
java:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
if (nums[0] > 0 || nums[n-1] < 0) {
return ans;
}
if (nums[0] == 0 && nums[n-1] == 0) {
ans.add(new ArrayList<>(Arrays.asList(0, 0, 0)));
return ans;
}
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] == nums[i-1]) {
continue;
}
if (nums[i] > 0) {
break;
}
int left = i + 1;
int right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
ans.add(new ArrayList<>(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) {
right--;
}
else {
left++;
}
}
}
return ans;
}
}