双指针——leetcode15——三数之和
#include <iostream> #include <vector> #include <algorithm> using namespace std; /*原理:双指针法 先将数组排序! 设定一个 p ,然后设定左指针 L = p + 1 ,右指针 R = size - 1 ; 要逼近的数是0,所以: 当p、L、R指向的数 之和 > 0 时,L右移,使和变小;(数组已排序,L右移必然变小) 当p、L、R指向的数 之和 < 0 时,R左移,使和变大; 当p、L、R指向的数 之和 = 0 时,得到结果,可以使L左移。 当 L > = R 时,说明此时没有更多的解,因此使p左移,直到nums[p]>0。因为nums[p]必定是三个指针的数中最小的值,所以nums[p]>0时不再有解,结束循环。 注意所有指针左移或者右移的过程中,都要跳过重复的数,防止重复解。 */ class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { //原理:双指针法 int size = nums.size(); vector<vector<int>> sol; vector<int> eq0; if (nums.size() == 0 || nums.size() == 1 || nums.size() == 0) //特殊情况 return sol; sort(nums.begin(), nums.end()); int p = 0, L = 0, R = 0; while (nums[p] <= 0 && p < size - 2) { L = p + 1; R = size - 1; while (L < R) { if (nums[p] + nums[L] + nums[R] > 0) { R--; while (nums[R + 1] == nums[R] && R < size - 1) R--; continue; } if (nums[p] + nums[L] + nums[R] < 0) { L++; while (nums[L - 1] == nums[L] && L < size - 1) L++; continue; } if (nums[p] + nums[L] + nums[R] == 0) { eq0.clear(); eq0.push_back(nums[p]); eq0.push_back(nums[L]); eq0.push_back(nums[R]); sol.push_back(eq0); L++; while (nums[L - 1] == nums[L] && L < size - 1) L++; continue; } } p++; while (nums[p - 1] == nums[p] && p < size - 1) p++; } return sol; } }; int main() { Solution s; vector<int> v = { 0,0,0,0 }; s.threeSum(v); cout << endl; }
参考:LeetCode 101 - A LeetCode Grinding Guide (C++ Ver)
双指针的适用范围:遍历数组,找出符合条件两个数 / 多个数。
双指针的使用:两个指针指向不同的元素,协同完成任务。也可以延伸到多个数组的多个指针。
双指针的类型:
1、若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域即为当前的窗口),经常用于区间搜索。
2、若两个指针指向同一数组,但是遍历方向相反,则可以用来进行搜索,待搜索的数组往往是排好序的。
/*原理:双指针法
先将数组排序!
设定一个 p ,然后设定左指针 L = p + 1 ,右指针 R = size - 1 ;
要逼近的数是0,所以:
当p、L、R指向的数 之和 > 0 时,L右移,使和变小;(数组已排序,L右移必然变小)
当p、L、R指向的数 之和 < 0 时,R左移,使和变大;
当p、L、R指向的数 之和 = 0 时,得到结果,可以使L左移。
当 L > = R 时,说明此时没有更多的解,因此使p左移,直到nums[p]>0。因为nums[p]必定是三个指针的数中最小的值,所以nums[p]>0时不再有解,结束循环。
注意所有指针左移或者右移的过程中,都要跳过重复的数,防止重复解。
*/
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> ret; sort(nums.begin(), nums.end()); //--先排序,目的:跳过重复解、用双指针逼近0 if (nums.size() <= 2) { //--特殊情况 return ret; } vector<int>::iterator p = nums.begin(); //--起始指针 vector<int>::iterator L = p + 1; //--左移指针 vector<int>::iterator R = nums.end() - 1; //--右移指针 int sum;//记录三指针的和 while (p <= nums.end() - 1 - 2 && *p <= 0) { //--设定p的范围; //特殊优化方法:当p>0时,p右边必定都>0,所以sum必大于0,所以结束循环 sum = *p + *L + *R; if (sum == 0) {//记录符合的解 vector<int> temp; temp.push_back(*p); temp.push_back(*L); temp.push_back(*R); ret.push_back(temp); do { L++; } while (*(L - 1) == *L && L != nums.end() - 1); } if (sum < 0) { do { L++; } while (*(L - 1) == *L && L != nums.end() - 1);//--左指针的移动方式, //--即:跳过重复解;防止溢出 } if (sum > 0) { do { R--; } while (*(R + 1) == *R && R != nums.begin());//--右边指针的移动方式,与左指针的同理 } if (L >= R) { //--判断:指针位置是否符合双指针的性质,否则已经没有解,移动起始指针p,重置L和R do { p++; } while (*(p - 1) == *p && p <= nums.end() - 1 - 2); L = p + 1; R = nums.end() - 1; } } return ret; } };
浙公网安备 33010602011771号