BM54 三数之
描述
给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
数据范围:,数组中各个元素值满足
空间复杂度:
,时间复杂度
注意:
- 三元组(a、b、c)中的元素可以按任意顺序排列。
- 解集中不能包含重复的三元组。
示例1
输入:
[-10,0,10,20,-10,-40]
复制返回值:
[[-10,-10,20],[-10,0,10]]
复制
示例2
输入:
[-2,0,1,1,2]
复制返回值:
[[-2,0,2],[-2,1,1]]
复制
示例3
输入:
[0,0]
复制返回值:
[]
题解
方法一:暴力求解
略~~
方法二:先排序,然后再使用双指针求解
假设数组为num,长度为n
步骤:
- 先将按升序数组排序
- 从索引i=0到i=n - 2进行遍历,索引为i的值为num[i],假设存在另外索引k,j的值满足num[i] + num[k] + num[j] = 0,那么只需要在[i+1,n-1]区间找到两个数字满足num[k] + num[j] == - num[i]即可
- 通过第二步分析,三数之和变成了两数之和。假设索引k < j,那么一定有num[k] < num[j],假设num[k] + num[j] = val
- 当val == -num[i]的时候直接返回i,k,j
- 当val > -num[i]的时候说明k、j的和过大,要在该区间找一个比较小的和,此时只能将j左移,因为如果k右移会导致num[k]增大
- 如果val < -num[i],则k右移
- 如果val == -num[i],则应该将后序数组中和num[k]、num[j]值相等的索引也跳过
- 在求解的过程中要做去重,假设我们已经将索引为i处的进行了求解,那么 如果num[i + 1] == num[i]则可以直接跳过,因为这些都是重复的解
代码如下:
std::vector<std::vector<int>> threeSum(std::vector<int> &num)
{
std::vector<std::vector<int>> ans;
if (num.size() < 3)
{
return ans;
}
std::sort(num.begin(), num.end());
for (int i = 0; i < num.size() - 2; ++i)
{
if (i > 0 && num[i] == num[i - 1])
{
continue;
}
int left = i + 1;
int right = num.size() - 1;
while (left < right)
{
int target = -num[i];
int sum = num[left] + num[right];
if (sum == target)
{
ans.push_back({num[i], num[left], num[right]});
while (left + 1 < right && num[left] == num[left + 1])
{
left++;
}
while (right - 1 > left && num[right] == num[right - 1])
{
right--;
}
left++;
right--;
}
else if (sum > target)
{
right--;
}
else
{
left++;
}
}
}
return ans;
}