目录
题目描述:
给定一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
解题思路:
- 先从小到大排序;
- 固定一个寻找另外两个数,遍历数组,定三个索引,当前 i = 0视为第一个数字,另外两个分别是L = i+1, R = nums.end()-1;
- 判断三个数之和是否为0,等于0,则添加记录;如果小于0,则总和过小,L++;如果大于0,R--;
问题的关键是去除重复,情况如下:
(1)i指向重复:当前索引i>0,且与前一个数字相等,重复
比如[-10,-6,-6, 2,4,9], i=1和i=2都是-6,当i=1时,然后通过L和R找后面两个数字,与i=2时,找后面的数字重复了,所以遇到重复的,则不再重复使用,跳过,即不使用i=2,直接用后面的,从i=3开始继续找左右两个数字。
(2)L或者R指向的数字重复:比如[-10,-7,8,8,9,10], 当i=0是,L=2和L=3指向的都是8,重复了,跳过,直接指向后面一个。
C++代码:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
//
int nums_len = nums.size();
if (nums_len < 3) return {};
// 排序
sort(nums.begin(), nums.end());
// 依次将当前数字nums[i]视为第一个数字,在后面寻找其他两个数字
vector<vector<int>> ans;
for (int i = 0; i < nums_len-2; i++)
{
// 有序数组,第一个数字就大于0
if (nums[i] > 0) return ans;
// 当前的数字nums[i]和前面的数字重复,则不再判断,跳过
if (i > 0 && nums[i] == nums[i-1]) continue; // i>0必须放前面
//
int L = i+1;
int R = nums_len-1;
while (L < R)
{
int sum_val = nums[i] + nums[L] + nums[R];
if (sum_val == 0)
{
ans.push_back({nums[i], nums[L], nums[R]}); // 记录当前合适的,再看看后面是否存在重复的
while (L < R && nums[L] == nums[L+1]) L++; // 去重,取后面索引,有序数组[-10,-6,-6, 2,4,16],当前i=0,L=1,R=5,则L=1时重复了
while (L < R && nums[R] == nums[R-1]) R--; // 去重,取前面索引,有序数组
L++;
R--;
}
else if (sum_val < 0) L++;
else R--;
}
}
return ans;
}
};
Python代码:
执行用时:396 ms, 在所有 Python 提交中击败了73.70%的用户
内存消耗:18.7 MB, 在所有 Python 提交中击败了23.58%的用户
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
# 排序
nums.sort()
# 长度不够
nums_len = len(nums)
if nums_len < 3: return []
# 固定当前数字为三个数字中的第一个,再寻找其他两个数字
# 使用左右指针指向nums[i]后面的两端,确认是否符合条件
# 事情的关键是如何去除重复的
ans = []
for i in range(nums_len-2):
if nums[i] > 0: return ans # 有序列表,第一数字就大于0,那总和肯定不会等于0
# 如当前索引i>0,且与前一个数字相等,重复
# 比如[-10,-6,-6, 2,4,9], 当i=2时,即当前数字是-6,当前数字-6已经在i=1时作为第一个数用过一次了,重复
if i > 0 and nums[i] == nums[i-1]: continue # i = i+1,即数字2作为第一个数
L = i+1
R = nums_len - 1
while L < R:
sum_val = nums[i] + nums[L] + nums[R]
if sum_val == 0:
ans.append([nums[i], nums[L], nums[R]]) # 找到当前合适的,在确认后面的是否重复。
while L<R and nums[L] == nums[L+1]: L = L + 1 # 去重,取后面索引,有序列表[-10,-6,-6, 2,4,16],当前i=0,L=1,R=5,则L=1时重复了
while L<R and nums[R] == nums[R-1]: R = R - 1 # 去重,取前面索引,有序列表
L = L + 1 # -6用过了,直接跳过2个-6,指向后面的2
R = R - 1
elif sum_val < 0: L = L + 1
else: R = R - 1
return ans