基于leetcode的算法训练:Day6

这次基本都是滑动窗口类型的题目了捏

2.10 字符串中的变位词

题目描述:给定两个字符串 s1s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。

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

题目链接剑指 Offer II 014. 字符串中的变位词 - 力扣(LeetCode)

题目难度:✨

AC题解

总体的思路:

  • 当s2字符串长度小于s1字符串,果断false
  • 滑动窗口的思想,引入对于len1长度子串的统计数组v1和v2,c++中可以直接判断v1和v2是否相等,相等则返回true否则继续滑动,更新v2
class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        //第一个字符串的排位之一是第二个字符串的子串
        vector<int>v1(26,0);
        vector<int>v2(26,0);
        int len1=s1.length();
        int len2=s2.length();
        if(len2<len1){
            return false;
        }
        for(int i=0;i<len1;i++){
            v1[s1[i]-'a']++;
        }
        bool flag=false;
        int left=0;
        int right=len1;
        for(;left<len1;left++){
            v2[s2[left]-'a']++;
        }
        if(v1==v2){
            return true;
        }else{
            left=0;
            //滑动窗口
            for(;right<len2;right++){
                v2[s2[left]-'a']--;
                v2[s2[right]-'a']++;
                left++;
                if(v1==v2){
                    return true;
                }
            }
            return false;
        }
    }
};

2.11 字符串中的所有变位词

题目描述:给定两个字符串 s 和 p,找到 s 中所有 p 的 变位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

变位词 指字母相同,但排列不同的字符串。

题目链接剑指 Offer II 015. 字符串中的所有变位词 - 力扣(LeetCode)

题目难度:✨

AC题解

思路同上一题,滑动窗口,只不过输出的内容不一样~

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int>ans;
        int len1=p.length();
        int len2=s.length();
        if(len1>len2){
            return ans;
        }else{
            vector<int>v1(26,0);
            vector<int>v2(26,0);
            for(int i=0;i<len1;i++){
                v1[p[i]-'a']++;
                v2[s[i]-'a']++;
            }
            int left=0;
            int right=len1;
            for(;right<len2;right++){
                if(v1==v2){
                    ans.push_back(left);
                }
                //滑动窗口
                v2[s[left]-'a']--;
                v2[s[right]-'a']++;
                left++;
            }
            if(v2==v1){
                ans.push_back(left);
            }
            return ans;
        }
    }
};

2.12 不含重复字符的最长子字符串

题目描述:给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。

题目链接剑指 Offer II 016. 不含重复字符的最长子字符串 - 力扣(LeetCode)

题目难度:✨

AC题解

根据百度我们知道ASCII码有128个,于是定义pos数组存储当前指针之前出现某个字符的最近的位置

思路依然是滑动窗口,left指向窗口最左边,当前指针i(指向窗口最右边)所指的字符在之前出现过且在窗口中(即pos[s[i]]>=left)窗口滑动,更新left

每次都需要计算当前窗口大小,若大于ans则更新ans,每一次指针移动都要更新pos数组的信息

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len=s.length();
        vector<int>pos(128,-1);//存放某个字符遍历到某个位置之前最后一次出现的位置
        int ans=0;
        int left=0;
        for(int i=0;i<len;i++){
            if(pos[s[i]]!=-1&&pos[s[i]]>=left){
                left=pos[s[i]]+1;
            }
            pos[s[i]]=i;
            if(i-left+1>ans){
                ans=i-left+1;
            }
        }
        return ans;
    }
};

2.13 含所有字符的最短字符串

题目描述:给定两个字符串 s 和 t 。返回 s 中包含 t 的所有字符的最短子字符串。如果 s 中不存在符合条件的子字符串,则返回空字符串 “” 。

如果 s 中存在多个符合条件的子字符串,返回任意一个。


题目链接剑指 Offer II 017. 含有所有字符的最短字符串 - 力扣(LeetCode)

题目难度:✨✨

AC题解

纪念一下独自做出hard(虽然不是最简洁的解法)

依然是滑动窗口的思路,每次向右移动根据记录的数组v1v2决定要不要移动左边窗口位置……不是很难理解,直接上代码

class Solution {
public:
    string minWindow(string s, string t) {
        int len1=t.length();
        int len2=s.length();
        if(len1>len2){
            return "";
        }else if(len1==len2&&len1==1){
            if(s==t)
                return s;
            else
                return "";
        }
        vector<int>v1(60,0);
        vector<int>v2(60,0);
        for(int i=0;i<len1;i++){
            if(t[i]<='z'&&t[i]>='a'){
                v1[t[i]-'a']++;
            }else{
                v1[t[i]-'A'+26]++;
            }
        }
        string ans="";
        int min_len=len2*2;
        int left=0;
        int right=0;
        for(;right<len2;right++){
            //更新右边
            if(s[right]<='z'&&s[right]>='a'){
                v2[s[right]-'a']++;
            }else{
                v2[s[right]-'A'+26]++;
            }
            //更新左边
            while(left<right){
                int id;
                if(s[left]<='z'&&s[left]>='a'){
                    id=s[left]-'a';
                }else{
                    id=s[left]-'A'+26;
                }
                if(v2[id]>v1[id]){
                    v2[id]--;
                    left++;
                }else{
                    break;
                }
            }
            //判断v1和v2是否符合条件
            bool flag=true;
            for(int x=0;x<52;x++){
                if(v2[x]<v1[x]){
                    flag=false;
                    break;
                }
            }
            if(flag){
                if(right-left+1<min_len){
                    min_len=right-left+1;
                    ans=s.substr(left,min_len);
                }
                //printf("合法:%d-%d:%d\n",left,right,right-left+1);
            }
        }
        bool flag=true;
            for(int x=0;x<52;x++){
                if(v2[x]<v1[x]){
                    flag=false;
                    break;
                }
            }
            if(flag){
                if(right-left+1<min_len){
                    min_len=right-left+1;
                    ans=s.substr(left,min_len);
                }
                //printf("合法:%d-%d:%d\n",left,right,right-left+1);
            }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值