题目描述:
给你一个整数数组 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] 。 注意,输出的顺序和三元组的顺序并不重要。
实现逻辑:
要找到数组中符合要求的三个数其实并不难,无所谓就是先定住一个指针i,使 i 作为for循环的 作用因子进行逐个遍历,同时在for循环内部再使用一个循环,设计两个指针left和right将i以外的所有位置都遍历一遍,同时避免i=left,i=right,left=right的任一情况发生。但是从示例中也可以看到,其实数组中会有重复数字的出现,这就导致了最后返回的容器中可能会有重复的,显然这不符合要求。为了避免重复,需要对重复元素跳过,而不能删除(否则如示例中的-1+-1+2的结果将会被误排除),而为了实现更高效的跳过操作,可以首先对所有元素进行排序操作。
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> result;int n = nums.size();if (n < 3) return result; // 如果数组长度小于3,直接返回空结果sort(nums.begin(), nums.end()); // 对数组进行排序for (int i = 0; i < n - 2; ++i) {if (i > 0 && nums[i] == nums[i - 1]) continue; // 跳过重复的元素int left = i + 1, right = n - 1;while (left < right) {int sum = nums[i] + nums[left] + nums[right];if (sum == 0) {result.push_back({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) {left++;} else {right--;}}}return result;}
};
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> result;int n = nums.size();if (n < 3) return result; // 如果数组长度小于3,直接返回空结果sort(nums.begin(), nums.end()); // 首先对数组进行排序for (int i = 0; i < n; ) {int target = -nums[i]; // 将问题转换为两数之和的问题int front = i + 1, back = nums.size() - 1;while (front < back) { // 使用双指针查找两个数,使这两个数的和等于-targetint sum = nums[front] + nums[back];if (sum < target) {++front; // 如果当前和小于目标值,则移动前指针增加总和} else if (sum > target) {--back; // 如果当前和大于目标值,则移动后指针减少总和} else {// 找到一组解,添加到结果集中vector<int> triplet(3, 0);triplet[0] = nums[i];triplet[1] = nums[front];triplet[2] = nums[back];result.push_back(triplet);// 跳过重复项while(front < back && nums[front] == triplet[1]) ++front;while(front < back && nums[back] == triplet[2]) --back;}}// 跳过重复项while (i + 1 < nums.size() && nums[i + 1] == nums[i]) ++i;++i;}return result;}
};