双指针——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; } };

 

posted on 2021-01-18 23:13  平ping  阅读(79)  评论(0)    收藏  举报