Day26[26/3/26]T15三数之和
给你一个整数数组 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-105 <= nums[i] <= 105
解题思路
- 先排序,因为排序之后才能用双指针快速搜索两个数字
- 先固定好第一个数字
nums[i]然后目标就是找到两个数,和为-nums[i] - 用双指针找到剩下的两个数字
- 这里你需要注意的就是,因为输出结果要求去重,所以你在搜索的时候,遇到重复元素就需要跳过
双指针法:
首先你对一个数组进行排序,然后左指针最左,右指针最右。
然后求取 sum,对比目标值,如果 sum 大了,那么右指针左移,如果小了则左指针右移,如果相等,那么就是找到结果了,然后随意移动一个指针寻找下一个即可。
循环条件就是左右指针没有相遇。
Code
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution
{
public:
vector<vector<int>> threeSum(vector<int> &nums)
{
vector<vector<int>> result;
// 1. 先排序
sort(nums.begin(), nums.end());
// 2. 遍历固定第一个数字
for (int i = 0; i + 2 < nums.size(); i++)
{
// 如果和上次一样,那么就要跳过,防止重复
if (i && nums[i - 1] == nums[i])
{
continue;
}
// 3. 双指针搜索
int target = -nums[i];
int left = i + 1;
int right = nums.size() - 1;
while (left < right)
{
// 双指针逻辑
int sum = nums[left] + nums[right];
if (sum > target)
{
right--;
}
else if (sum < target)
{
left++;
}
else
{
// cout << " i, left, right :" << i << left << right << endl;
// 4. 出现答案,记录下并且继续搜索
result.push_back({nums[i], nums[left], nums[right]});
left++;
// 这里进行去重,只需要确保左指针指向的值变化了就行
while (left < nums.size() && nums[left] == nums[left - 1])
{
left++;
}
}
}
}
return result;
}
};
auto main() -> int
{
// vector<int> nums{-1, 0, 1, 2, -1, -4};
vector<int> nums{0, 0, 0, 0};
Solution sol;
vector<vector<int>> result = sol.threeSum(nums);
for (const auto &row : result)
{
cout << "[ ";
for (const auto &index : row)
{
cout << index << ",";
}
cout << " ]" << endl;
}
}