雙指針專題

424. 替換後的最長重複字符

給你一個僅由大寫英文字母組成的字符串,你能夠將任意位置上的字符替換成另外的字符,總共可最多替換 k 次。在執行上述操做後,找到包含重複字母的最長子串的長度。css

 若是咱們按序遍歷每一個字符開始計算符合條件的子串長度,對於每一個子串,咱們只須要以它的第一個字符爲不變字符。思路簡單,代碼清晰,耗時巨長,加了一個遇連續相同字符直接跳過,以及i到達的字符開始的子串不可能爲最大時結束,才勉強AC數組

int characterReplacement(string s, int k) {
        int n=s.length();
        int ans=0;
        for(int i=0;i<s.length();i++){
            if(i>0&&s[i]==s[i-1])continue;
            if(s.length()-i+k<=ans)return ans;
            char c=s[i];
            int tmp=0;
            for(int j=i+1;j<s.length();j++){
                if(s[j]!=c)tmp++;
                if(tmp>k){
                    ans=max(ans,j-i);
                    break;
                }
            }
            if(tmp<=k)
                ans=max(ans,min((int)s.length(),(int)s.length()-i+k-tmp));
        }
        return ans;
    }

 

這題是典型的雙指針問題,或者,滑動窗口問題。不須要保存每個窗口內的字母出現的最大值,由於字母必定是從右邊新添的字符裏出現,並且只有當窗口內出現了比歷史更多的字母數時,答案纔會更新,也就是maxCnt不須要是實時的最大字母數。oop

int characterReplacement(string s, int k) {
        int n=s.length();
        int ans=0,left=0,maxCnt=0;
        vector<int> letter(26,0);
        for(int i=0;i<s.length();i++){
            letter[s[i]-'A']++;
            maxCnt=max(maxCnt,letter[s[i]-'A']);
            if(i-left+1-maxCnt>k){
                letter[s[left]-'A']--;
                left++;
            }
            ans=max(ans,i-left+1);
        }
        return ans;
    }

 

457. 環形數組循環

給定一個含有正整數和負整數的環形數組 nums。 若是某個索引中的數 k 爲正數,則向前移動 k 個索引。相反,若是是負數 (-k),則向後移動 k 個索引。由於數組是環形的,因此能夠假設最後一個元素的下一個元素是第一個元素,而第一個元素的前一個元素是最後一個元素。spa

肯定 nums 中是否存在循環(或週期)。循環必須在相同的索引處開始和結束而且循環長度 > 1。此外,一個循環中的全部運動都必須沿着同一方向進行。換句話說,一個循環中不能同時包括向前的運動和向後的運動。指針

原方法:code

用一個數組vis記錄
vis[i]=k表示 結點 i 是從下標 k 爲起始點出發所能到達的路徑上的點
每次從未探索過的i出發找大於1的環blog

bool circularArrayLoop(vector<int>& nums) {
        int n=nums.size();
        vector<int> vis(n,-1);
        for(int i=0;i<n;i++)
        {
            if(vis[i]>=0&&vis[i]<i)continue;
            int t=i;
            bool flag=nums[i]>0?true:false;
            while(flag==(nums[t]>0)){       //flag保證同方向
                if(vis[t]==i){
                    int len=0;
                    int k=(t+nums[t]+n)%n;
                    while(k<0)k=(k+n);          //保證下標爲正
                    while(k!=t){
                        k=(k+nums[k]+n)%n;
                        while(k<0) k=(k+n);
                        len++;
                        if(len>0) return true; 
                    }                   //計算環的長度
                    break;           //從i出發僅有1單位長度的環,繼續從i+1開始找
                }
                if(vis[t]!=-1)break;   //跑到以前走過的路上去了,以前無解,此次也無解 
                vis[t]=i;
                t=(t+n+nums[t])%n;
                while(t<0)t=(t+n);
            }
        }
        return false;
    }

 

改進方法:既然是雙指針的問題,又有環,那快慢指針確定沒跑了索引

int idx(int i, int dx,int n){
        if(dx>0)return (i+dx)%n;
        else return (i-abs(dx)%n+n)%n;
    }
bool circularArrayLoop(vector<int>& nums) {
        int n=nums.size();
        vector<int> vis(n,-1);
        for(int i=0;i<n;i++)
        {
            if(vis[i]!=-1)continue;
            int slow=i,fast=i;

            while(nums[slow]*nums[fast]>0&&nums[slow]*nums[idx(fast,nums[fast],n)]>0){
                slow=idx(slow,nums[slow],n);
                if(vis[slow]!=-1&&vis[slow]!=i)break;vis[slow]=i;

                fast=idx(fast,nums[fast],n);
                if(vis[fast]!=-1&&vis[fast]!=i)break;vis[fast]=i;

                fast=idx(fast,nums[fast],n);
                if(vis[fast]!=-1&&vis[fast]!=i)break;vis[fast]=i;

                if(fast==slow){
                    if(idx(slow,nums[slow],n)!=slow)return true;
                    break;
                }
                
            }
        }
        return false;
    }

待更新。。。ci

相關文章
相關標籤/搜索