76最小覆盖字串

前言

这是我力扣的第172道题,也是力扣100热题的第96道;之前遇到题5分钟没有思路就去看题解了;我发现再做笔试题的时候,因为有时间限制,而且没有答案可以看,就会很专心,尝试一些办法去写;但是平时练习的时候,因为太过轻松,一些能自己实现的题也会因为各种题解的存在而不自己尝试;这就是长进不太大的原因;今天给自己2个小时的时候去调试这道题,就是一个开端;

题目描述

题目传送门:76最小覆盖字串
在这里插入图片描述
这道题可以简化为求子集问题,但是有个限定条件就是要求字符出现的前后顺序一致才行;题目就简化为求字符串s中满足子串包括字符串t的最短的字符串;这个题好像与上周的美团笔试编程第四题类似;但是只有47%的通过率,现在已经明白是因为按照我的解题思路,没有字符的顺序;

暴力解法


我的第一版答案(178 / 266)

在这里插入图片描述

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char,int> t_map1;
        unordered_map<char,int> flag;
        int out = 0;
        string str_res;
        for(char c:t)
        {
            t_map1[c]++;
            flag[c] = 0;
        }
        for(int j = 0;j<s.size();j++)
        {
            unordered_map<char,int> t_map;
            int res=0;
            string str_temp;
            t_map = t_map1;
            for(int i=j;i<s.size();i++)
            {
                str_temp.push_back(s[i]);
                if(t_map.find(s[i]) == t_map.end())
                    continue;
                t_map[s[i]] --;
                res++;
                //if(t_map[s[i]]<0)
                //    break;
                if(t_map == flag)
                {
                    str_res = res>out ? str_temp : str_res;
                    out = min(res,out);
                    break;
                } 
            }    
        }
        return str_res;

    }
};

原因是没有考虑字符的顺序,所以当输入为"aefgc"时,就错误了;可见前边的177个实例都是按照顺序排列的;

第二版答案

日了狗了,原来字符顺序可以不一样,用queue写了一遍,才发现如果要求字符出现的顺序一致根本不符合题意,但是干事记录一下吧,其他类型的题目可能用得上

class Solution {
public:
    string minWindow(string s, string t) {
        queue<char> t_que;
        string res_str;
        int res_L = INT_MAX;
        for(auto tt:t)
        {
            t_que.push(tt);
        }
        int L = s.size();
        for(int i=0;i<L;i++)
        {
            int temp_L = 0;
            string temp_str;
            queue<char> flag = t_que;
            for(int j =i;j<L;j++)
            {
                temp_L++;
                temp_str.push_back(s[j]);
                if(s[j]==flag.front())
                    flag.pop();
                if(flag.empty())
                {
                    res_L = min(temp_L,res_L);
                    res_str = (res_L == temp_L ? temp_str : res_str);                  
                }
            }
        }
        return res_str;
    }
};

在这里插入图片描述
如果要求字符顺序一致,确实是这个结果;所以说第一版出错并不是因为题意错了;

第三版答案(192/266)

在这里插入图片描述

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char,int> t_map1;
        unordered_map<char,int> flag;
        int out = INT_MAX;
        string str_res;
        for(char c:t)
        {
            t_map1[c]++;
            flag[c] = 0;
        }
        for(int j = 0;j<s.size();j++)
        {
            unordered_map<char,int> t_map;
            int res=0;
            string str_temp;
            t_map = t_map1;
            for(int i=j;i<s.size();i++)
            {
                str_temp.push_back(s[i]);
                res++;
                if(t_map.find(s[i]) == t_map.end())
                    continue;
                t_map[s[i]] --;
                
                //if(t_map[s[i]]<0)
                //    break;
                if(t_map == flag)
                {
                    out = min(res,out);
                    str_res = (out==res ? str_temp : str_res);
                    break;
                } 
            }    
        }
        return str_res;

    }
};

与第一版相比,就修改了res++的位置,还是本都ide调试舒服;但是又出现了问题;

第四版答案(265/266)

在这里插入图片描述

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char,int> t_map1;
        unordered_map<char,int> flag;
        int out = INT_MAX;
        string str_res;
        for(char c:t)
        {
            t_map1[c]++;
            flag[c] = 0;
        }
        for(int j = 0;j<s.size();j++)
        {
            unordered_map<char,int> t_map;
            int res=0;
            string str_temp;
            t_map = t_map1;
            for(int i=j;i<s.size();i++)
            {
                str_temp.push_back(s[i]);
                res++;
                if(t_map.find(s[i]) == t_map.end() || (t_map.find(s[i]) != t_map.end() && t_map[s[i]]==0))
                    continue;
                t_map[s[i]] --;
                
                //if(t_map[s[i]]<0)
                //    break;
                if(t_map == flag)
                {
                    out = min(res,out);
                    str_res = (out==res ? str_temp : str_res);
                    break;
                } 
            }    
        }
        return str_res;

    }
};

比起第三版,再if语句哪里加了一个判定条件;观察第三个版本的错误案例
在这里插入图片描述
发现与之前的案例不同的是,他有重复的元素;所以需要添加条件;因为map的key可以为负数;就算已经减为0,那么键值还是存在的,可以找到;所以再与flag比较的时候就不相等;但是第265个例子时间复杂富超了;哈哈哈,暴力解法果真不行;

第五版答案(265/266)

第四版答案再判断字符是否再map中时,为了防止重复元素是的map对应的键变为负值,加了判断map对应键的值是否为0的操作,但是这种写法就会阻挡判断map是否等于flag的判断;假设说
s = “abcccccccccccccccccccccccccc(10000个)”
t = “aaabbbc”
本来再s中,第一个c出现以后就可以结束这次循环;但是因为因为加入的条件,就会导致一直遍历到字符串的结尾;这就浪费了大量的时间;所以我们换种写法;

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char,int> t_map1;
        unordered_map<char,int> flag;
        int out = INT_MAX;
        string str_res;
        for(char c:t)
        {
            t_map1[c]++;
            flag[c] = 0;
        }
        for(int j = 0;j<s.size();j++)
        {
            unordered_map<char,int> t_map;
            int res=0;
            string str_temp;
            t_map = t_map1;
            for(int i=j;i<s.size();i++)
            {
                str_temp.push_back(s[i]);
                res++;
                if(t_map.find(s[i]) == t_map.end())
                    continue;
                t_map[s[i]] --;
                if(t_map[s[i]]==-1)
                    t_map[s[i]]++;
                
                if(t_map == flag)
                {
                    out = min(res,out);
                    str_res = (out==res ? str_temp : str_res);
                    break;
                } 
            }    
        }
        return str_res;

    }
};

结果与第四版一样,265/266;所以这道题暴力解法差点意思;
所以到了去看题解的时候了;
题解用了滑动窗口加收缩指针的方法;这种方法我最开始也这么想过,但是我居然以为跟我现在的暴力复杂度一样,就没尝试;


滑动窗口+收缩指针(官解)

class Solution {
public:
    unordered_map <char, int> ori, cnt;

    bool check() {
        for (const auto &p: ori) {
            if (cnt[p.first] < p.second) {
                return false;
            }
        }
        return true;
    }

    string minWindow(string s, string t) {
        for (const auto &c: t) {
            ++ori[c];
        }

        int l = 0, r = -1;
        int len = INT_MAX, ansL = -1, ansR = -1;

        while (r < int(s.size())) {
            if (ori.find(s[++r]) != ori.end()) {
                ++cnt[s[r]];
            }
            while (check() && l <= r) {
                if (r - l + 1 < len) {
                    len = r - l + 1;
                    ansL = l;
                }
                if (ori.find(s[l]) != ori.end()) {
                    --cnt[s[l]];
                }
                ++l;
            }
        }

        return ansL == -1 ? string() : s.substr(ansL, len);
    }
};


滑动窗口+收缩指针(自解)

class Solution {
public:
    bool CHECK(unordered_map<char,int>& M1,unordered_map<char,int>&  M2,string& t)
    //M1是目标值,t构成的
    {
        for(auto tt:t)
        {
            if(M1[tt] > M2[tt])
                return false;
        }
        return true;
    }

    string minWindow(string s, string t) {
        unordered_map<char,int> t_map;
        int ansL = -1;
        int ansR = 0;
        int LL=0;
        int RR= -1;
        int res = INT_MAX;
        string res_str;
        if(t.size()>s.size())
            return res_str;
        for(auto tt:t)
            t_map[tt]++;
        unordered_map<char,int> s_map;

        for(int L=0;L<s.size();L++)
        {
            if(t_map.find(s[L])!=t_map.end())
                s_map[s[L]]++;
            
            while(CHECK(t_map,s_map,t))
            {  
                ansR = L;
                ansL++;
                int len = ansR-ansL+1;
                if(len<res)
                {
                    res = len;
                    RR = ansR;
                    LL= ansL;
                }
                if(t_map.find(s[ansL])!=t_map.end())
                {
                    s_map[s[ansL]]--;
                }
            }
        }
        return s.substr(LL,RR-LL+1);

    }
};

我觉得我的复杂度与官方复杂度一样,可是结果还是256/266;至于为什么之后再看吧

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星光技术人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值