Hot 100 刷题日记三 滑动数组、子串(无重复字符的最长子串、找到字符串中所有字母异位词、和为 K 的子数组、滑动窗口最大值、最小覆盖子串)

无重复字符的最长子串

. - 力扣(LeetCode)

思路:用set维护一个滑动窗口,保证其中没有重复元素,如果遇到重复元素就从头部开始弹出

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int l = 0, ans = 0;
        unordered_set<char> st;
        
        for(int i=0; i<s.size(); i++)
        {
            while(st.find(s[i]) != st.end())
            {
                st.erase(s[l]);
                l++;
            }
            st.insert(s[i]);
            ans = max(ans, i-l+1);
        }

        return ans;
    }
};

找到字符串中所有字母异位词

. - 力扣(LeetCode)

思路:自定义一个数组用来检测,然后维护一个长度为p.size()的滑动窗口.

优化点:可以记录p中出现了哪些字母,如果出现了一个从未出现过的字母,那就可以跳过长的长度,重新开始  

上面的是负优化.这题没在这上面卡人,但这个优化是可以学一下的.

未优化版本

class Solution {
public:
    int cnt[27], mycnt[27];

    bool check(int x)
    {
        for(int i=0; i<26; i++)
        {
            if(cnt[i] != mycnt[i]) return false;
        }
        return true;
    }
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans;

        if(s.size() < p.size()) return ans;
        
        for(int i=0; i<p.size(); i++)
            cnt[p[i]-'a']++;

        for(int i=0; i<p.size(); i++)
            mycnt[s[i]-'a']++;
        
        
        for(int i=0; i+p.size() <= s.size(); i++)
        {
            if(check(i)) ans.push_back(i);

            //cout<<"cnt:    ";
            //for(int i=0; i<26; i++) cout<<cnt[i]<<" ";
            //cout<<endl;

            //cout<<"mycnt:  ";
            //for(int i=0; i<26; i++) cout<<cnt[i]<<" ";
           //cout<<endl;


            if(i+1+p.size() <= s.size())
            {
                mycnt[s[i]-'a']--;
                mycnt[s[i+p.size()]-'a']++;
            }
        }
        return ans;
    }
};

优化版本

class Solution {
public:
    int cnt[27], mycnt[27];

    bool check(int x)
    {
        for(int i=0; i<26; i++)
        {
            if(cnt[i] != mycnt[i]) return false;
        }
        return true;
    }
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans;
        set<char> st;

        if(s.size() < p.size()) return ans;

        for(int i=0; i<p.size(); i++) 
        {
            if(st.find(p[i]) == st.end()) st.insert(p[i]);
        }      

        for(int i=0; i<p.size(); i++)
            cnt[p[i]-'a']++;

        for(int i=0; i<p.size(); i++)
            mycnt[s[i]-'a']++;
        
        //remake记录是否需要重新录入
        bool remake = false;
        for(int i=0; i+p.size() <= s.size(); i++)
        {
            //未找到则标记 并跳过这个字母
            if(st.find(s[i]) == st.end())
            {
                remake = true;
                continue;
            }
            // 通过remake判断是否需要重新录入
            if(remake)
            {
                for(int i=0; i<26; i++) mycnt[i] = 0;
                for(int j = i; j<i+p.size(); j++)
                    mycnt[s[j]-'a']++;
            }

            if(check(i)) ans.push_back(i);

            if(i+1+p.size() <= s.size())
            {
                mycnt[s[i]-'a']--;
                mycnt[s[i+p.size()]-'a']++;
            }
        }
        return ans;
    }
};

滑动窗口最大值

思路:使用一个滑动窗口去维护最大值,前面的用滑动窗口长度去排除,后面的用数值关系去排除

class Solution {
public:
    int a[100010];
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int l = 0, r = -1;
        vector<int> ans;
        for(int i=0; i<nums.size(); i++)
        {
            if(l<=r && i-a[l] >= k) l++;
            while(l<=r && nums[a[r]] <= nums[i]) r--;
            a[++r] = i;

            if(i >= k-1)ans.push_back(nums[a[l]]);
        }
        return ans;
    }
};

最小覆盖子串

. - 力扣(LeetCode)

思路:思想有点类似双指针,还是维护一个滑动数组,如果l下标的数量多了,l左移,r随着for循环移动,每一次都去检查check,如果成立那就更新答案

注:这里我是用数组模拟的,但其实可以用map来做

class Solution {
public:
    int cnt[128], nowCnt[128];

    int findcnt(char x)
    {
        if(x >= 'A' && x <= 'Z')
            return cnt[x - 'A'];
        if(x >= 'a' && x <= 'z')
           return  cnt[x - 'a' + 30];
        return 1;
    }

    int findNowcnt(char x)
    {
        if(x >= 'A' && x <= 'Z')
            return nowCnt[x - 'A'];
        if(x >= 'a' && x <= 'z')
           return  nowCnt[x - 'a' + 30];
        return 1;
    }

    void cntadd(char x, int d)
    {
        if(x >= 'A' && x <= 'Z')
            cnt[x - 'A']+= d;
        if(x >= 'a' && x <= 'z')
            cnt[x - 'a' + 30]+= d;
    }

    void cntNowadd(char x, int d)
    {
        if(x >= 'A' && x <= 'Z')
            nowCnt[x - 'A'] += d;
        if(x >= 'a' && x <= 'z')
           nowCnt[x - 'a' + 30] += d;
    }

    bool useable(char x)
    {
        if(x >= 'A' && x <= 'Z')
            return findcnt(x) > 0;
        if(x >= 'a' && x <= 'z')
            return findcnt(x) > 0;
        return true;
    }

    bool check()
    {
        for(int i=0; i<56; i++)
            if(cnt[i] > nowCnt[i]) return false;
        return true;
    }

    string minWindow(string s, string t) {

        for(int i=0; i<t.size(); i++)
        {
            cntadd(t[i], 1);
        }
            
        int l = 0, r;
        bool finded = false;
        int minans = 3e5;
        int ansl = -1, ansr = -1;
        string ans = "";
        for(r=0; r<s.size(); r++)
        {
            //此时r这个字母是否是有用的
            if(!useable(s[r])) continue;
            cntNowadd(s[r], 1);

            while(l<r && ((findNowcnt(s[l]) > findcnt(s[l])) ||  findcnt(s[l])==0))
            {
                if(useable(s[l])) cntNowadd(s[l], -1);
                l++;
            }

            if(check() && (r - l + 1) < minans)
            {
                finded = true;
                minans = (r - l + 1);
                ansl = l, ansr = r;
            }
        }

        if(finded) ans = s.substr(ansl, ansr - ansl +1);
        return ans;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值