#双指针总结

这个算法可以用于解决从一个有序数值数组中从数组元素中取两个值,从而求得某个或某些个最值的情况
通常是算法思路都是同时在数组的第一位与最后一位放置一个指针,用这两个指针所在的值计算题目所需的结果,
根据当前计算结果与之前历史结果的比较,判断两个指针如何向内移动(是否移动,移动多少),两个指针重叠标志着程序结束

例题:

1.三数之和 (https://leetcode-cn.com/problems/3sum/)

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

思路:a+b+c==0的问题,我们可以先遍历a的值,然后在循环内从小到大遍历b的值,从大到小遍历c的值。

然后是去除重复值的情况:在一个循环内,如果num[i]==nums[i+1]那么这就是个重复值,我们有两层循环,两层都要去除重复值

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>>ans;
        int n = nums.size();
        if(n<3) return ans;
        int l,r;
        sort(nums.begin(),nums.end());
        for(int i = 0; i < n-2; i++){
            if(nums[i]>0) break;
            if(i>0 && nums[i] == nums[i-1]) continue;
            l = i+1;
            r = n-1;
            while(l<r){
                int sum = nums[i]+nums[l]+nums[r];
                if(sum == 0){
                    ans.push_back({nums[i],nums[l],nums[r]});
                    while(l<r && nums[l]==nums[l+1]) l++;
                    while(l<r && nums[r]==nums[r-1]) r--;
                    l++;r--;
                }
                else if(sum < 0) l++;
                else r--;
            }
            
        }
        return ans;
    }
};

2.四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,
使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

思路:和三数之和解法类似,这次需要先确定两个值,然后通过双指针寻找另外两个符合要求的值

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> ans;
        int n = nums.size();
        if(n<4) return ans;
        sort(nums.begin(),nums.end());
        for(int i=0;i<n-3;i++){
            if(i>0 && nums[i] == nums[i-1]) continue;
            if(i>0 && nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) break;
            if(i>0 && nums[i]+nums[n-1]+nums[n-2]+nums[n-3]<target) continue;
            for(int j=i+1;j<n-2;j++){
                if(j>i+1 && nums[j]==nums[j-1]) continue;
                if(nums[i]+nums[j]+nums[j+1]+nums[j+2]>target) break;
                if(nums[i]+nums[j]+nums[n-1]+nums[n-2]<target) continue;
                int l = j+1,r=n-1;
                while(l<r){
                    int sum = nums[i]+nums[j]+nums[l]+nums[r];
                    if(sum == target) {
                        ans.push_back({nums[i],nums[j],nums[l],nums[r]});
                        while(l<r && nums[l]==nums[l+1]) l++;
                        while(l<r && nums[r]==nums[r-1]) r--;
                        l++;
                        r--;
                    }
                    else if(sum<target) l++;
                    else r--;
                }
            }
            
        }
        return ans;
    }
};

3.统计子串中的唯一字符(https://leetcode-cn.com/problems/count-unique-characters-of-all-substrings-of-a-given-string/)

我们定义了一个函数 countUniqueChars(s) 来统计字符串 s 中的唯一字符,并返回唯一字符的个数。

例如:s = "LEETCODE" ,则其中 "L", "T","C","O","D" 都是唯一字符,因为它们只出现一次,所以 countUniqueChars(s) = 5 。

本题将会给你一个字符串 s ,我们需要返回 countUniqueChars(t) 的总和,其中 t 是 s 的子字符串。注意,某些子字符串可能是重复的,但你统计时也必须算上这些重复的子字符串(也就是说,你必须统计 s 的所有子字符串中的唯一字符)。

由于答案可能非常大,请将结果 mod 10 ^ 9 + 7 后再返回。

思路:将这些字串划分为不同的区间,然后对每个字符分别求解它对不同区间的贡献度

class Solution {
public:
    typedef long long ll;
    const ll mod = 1e9+7;
    int uniqueLetterString(string s) {
        int n = s.length();
        if(n==0) return 0;
        ll ans=0;
        vector<int>left(n,-1);
        vector<int>right(n,-1);

        //区间左端点
        vector<int>pre(26,-1);
        for(int i=0;i<n;i++){
            left[i]=pre[s[i]-'A'];
            pre[s[i]-'A'] = i;
        }

        //区间右端点
        for(int i=0;i<n;i++) pre[s[i]-'A'] = n;
        for(int i=n-1;i>=0;i--){
            right[i]=pre[s[i]-'A'];
            pre[s[i]-'A'] = i;
        }
        for(int i=0;i<n;i++){
            ans=(ans+(i-left[i])*(right[i]-i))%mod;
        }
        return ans;
    }
};
七月在野,八月在宇,九月在户,十月蟋蟀入我床下
原文地址:https://www.cnblogs.com/voids5/p/14357952.html