• #双指针总结


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

    例题:

    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;
        }
    };
    
    七月在野,八月在宇,九月在户,十月蟋蟀入我床下
  • 相关阅读:
    MSSQL server 2005 ALTER TABLE
    行业趋势:中国IT产业未来七大赚钱模式
    BLOG之路
    软件企业实施CMM/CMMI面临的五个关键问题
    CSV文件及其使用
    电脑操作最忌讳的18个小动作
    请收听舍得微博
    SuperMemo UX汉化要点
    发音、听力两不误——精简版Tell Me More训练方案
    舍得的十八般武器(常用电脑软件【2012版】)
  • 原文地址:https://www.cnblogs.com/voids5/p/14357952.html
Copyright © 2020-2023  润新知