三数之和_优选算法(C++)双指针
网页直达:
https://leetcode.cn/problems/1fGaJU
题目分析:
1.每个数只能选一次.
2.返回全部的不重复的三元组相加等于零的子数组.
一.暴力解法:(O(N^3))
排序+暴力枚举+利用set去重(容器去重).
二.排序+双指针法
1.排序;
2.固定一个数 a;
3.在该数后面的区间内,利用,单调性(可以筛选掉一大堆不成立的枚举)+双指针法,快速找到;;两个数为负a即可.
4.去重:可以利用set去重(容器去重).
利用unique先去重再寻找.
(优化):其实去重也可以利用单调性来实现,因为相同的数在排序的作用下已经在一起了,如果碰到相同的直接跳过就可以了.
这种题目需要多画图
我们通过几个图像过程来解析:
代码实现:
无详解:
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(), nums.end());vector<vector<int>> ret;int n = nums.size();for (int i = 0; i < n-2; i++) {if (nums[i] > 0)break; // 小优化if (i > 0 && nums[i] == nums[i - 1]) // 去重i{continue;}int right = n - 1;int left = i + 1;while (left < right) {int sum = nums[i] + nums[left] + nums[right];if (sum < 0) {left++;} else if (sum > 0) {right--;} else {ret.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--; // 找下一个,不漏掉全部情况}}}return ret;}
};
详解解析:
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(), nums.end());vector<vector<int>> ret;//储存结果int n = nums.size();for (int i = 0; i < n; i++) {if (nums[i] > 0)// 小优化,如果第一个数都大于零了,就不可能有成立的三元组了break; if (i > 0 && nums[i] == nums[i - 1]) // 去重i{continue;//本来应该是i++的,但是熟悉语法就可以用continue去重}int right = n - 1;int left = i + 1;//双指针while (left < right) {int sum = nums[i] + nums[left] + nums[right];if (sum < 0) {left++;} else if (sum > 0) {right--;} else {ret.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--; // 找下一个,不漏掉全部情况}}}return ret;}
};
细节:
这里我们演示一些细节问题:
1.去重(right,left,i去重):
2.越界的特殊情况:
3.我们需要找到全部符合的三元组,不要遗漏
也就是我们找到一组后,left++,right--找下一组.直到遍历完.