leetcode 滑动窗口和KMP

23 篇文章 0 订阅

最小覆盖子串

给你一个字符串 S、一个字符串 T 。请你设计一种算法,可以在 O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:

输入:S = “ADOBECODEBANC”, T = “ABC”
输出:“BANC”

class Solution {
public:
    string minWindow(string s, string t) {
        map<char,int> st;
        int needNum=t.size();
        char c;
        for(char c:t){
            if(st.count(c)==0){
                st[c]=0;
            }
            st[c]+=1;
        }
        int left=0;
        int right=100000000;
        
        int i=0;
        for(int j=0;j<s.size();j++){
            c=s[j];
            if(st.count(c)==0){
                st[c]=0;
            }else if(st[c]>0){
                needNum-=1;
            }
            st[c]-=1;
            if(needNum==0){
                while(i<=j){
                    if(st[s[i]]==0){
                        break;
                    }
                    st[s[i]]+=1;
                    i+=1;
                }
                if((j-i)<(right-left)){
                    left=i;
                    right=j;
                }
                needNum+=1;
                st[s[i]]+=1;
                i+=1;
            }
        }
        if(right==100000000){
            return "";
        }
        return s.substr(left,right-left+1);
    }
};

字符串的排列

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        map<char,int> init_map;
        map<char,int> cur_map;
        int len=s2.size();
        int init_needNum=0;
        int cur_needNum=0;
        for(char c:s1){
            if(init_map.count(c)==0){
                init_map[c]=0;
            }
            init_map[c]+=1;
            init_needNum+=1;
        }
        cur_needNum=init_needNum;
        cur_map=map<char,int>(init_map);
        int i=0;
        for(int j=0;j<len;j++){
            // for(auto k:cur_map){
            //     cout<<k.first<<cur_map[k.first];
            // }
            // cout<<endl;
            char c=s2[j];
            if(cur_map.count(c)>0){
                if(cur_map[c]>0){
                    cur_needNum-=1;
                    if(cur_needNum==0){
                        return true;
                    }
                    cur_map[c]-=1;
                }else{
                    while(i<=j){
                        char t=s2[i];
                        cur_needNum+=1;
                        cur_map[t]+=1;
                        if(t==c){
                            i=i+1;
                            break;
                        }
                        i=i+1;
                    }
                    cur_needNum-=1;
                    cur_map[c]-=1;
                }                
            }else{
                cur_needNum=init_needNum;
                cur_map=map<char,int>(init_map);
                i=j+1;
                if(i==(len-1)){
                    return false;
                }
            }
        }
        return false;
    }
};

简化版本

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        unordered_map<char, int> mp;
        for (auto &c: s1) mp[c]++; // 记录 出现次数的差值

        int l = 0, r = 0;
        while (r < s2.size()){
            char c = s2[r++];
            mp[c]--; // 入窗
            while (l < r && mp[c] < 0){ // 出窗
                mp[s2[l++]] ++;
            }
            if (r - l == s1.size()) return true;
        }
        return false;
    }
};

KMP

在这里插入图片描述

为了描述状态转移图,我们定义一个二维 dp 数组,它的含义如下:

dp[j][c] = next
0 <= j < M,代表当前的状态
0 <= c < 256,代表遇到的字符(ASCII 码)
0 <= next <= M,代表下一个状态

dp[4][‘A’] = 3 表示:
当前是状态 4,如果遇到字符 A,
pat 应该转移到状态 3

dp[1][‘B’] = 2 表示:
当前是状态 1,如果遇到字符 B,
pat 应该转移到状态 2

class Solution {
public:
    void KMP(vector<vector<int>> & dp , string & pat) {
        int len=pat.size();
        int x=0;
        dp[0][int(pat.at(0))]=1;
        for(int i=1;i<len;i++){
            for(int j=0;j<256;j++){
                if(j==int(pat.at(i))){
                    dp[i][j]=i+1;
                }else{
                    dp[i][j]=dp[x][j];
                }
            }
            x=dp[x][int(pat.at(i))];
        }
        return;
    } 
    int strStr(string haystack, string needle) {
        int len_n=needle.size();
        int len_h=haystack.size();
        if(len_n==0){
            return 0;
        }
        if(len_h==0){
            return -1;
        }
        int cur_state=0;
        vector<vector<int>> dp(len_n,vector<int>(256,0));
        KMP(dp,needle);
        for(int i=0;i<len_h;i++){
            cur_state=dp[cur_state][haystack.at(i)];
            // cout<<cur_state<<endl;
            if(cur_state==len_n){
                return i-len_n+1;
            }
        }
        return -1;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值