Leetcode 76 最小覆盖子串

Leetcode 76 最小覆盖子串

问题重述
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC” 输出:“BANC”
示例 2:
输入:s = “a”, t = “a” 输出:“a”

思路
这一题双指针例题,我们采用滑动窗口的思想。首先左右指针都在最左端,记录下出现了那些字符(我们用bool型数组flag记录),再记录下每一个字母出现了多少次(我们用int型数组chars记录)。

vector<int> chars(128, 0);
        vector<bool> flag(128, false);
        for (int i = 0; i < t.size(); ++i) {
            flag[t[i]] = true; //判断这个字符是不是在t里面出现过,比如字母a出现了就设置flag[a]为真
            ++chars[t[i]]; //看每一个字母出现了多少次,比如a出现了三次,所以最后chars[a] = 3
        }

循环里移动右指针。首先第一个我们要找的串肯定是包含t中出现所有字母。我们可以使用cnt记录,比如字母a是串t中的字符;s中出现一次a,我们将cnt++,并且记录数目的chars[a]减一。
以此类推一直到cnt==t.size的时候。再在一个循环里面移动左指针,如果此时找的串最左侧字符不是t中的字符,显然得到的串满足条件且比之前的串长度少一个,可以继续移动左指针。(所以我们可以使用while循环实现)。一直到最后,找到最短的串。

for (r = 0; r < s.size(); ++r) {
            if (flag[s[r]]) {
                if (--chars[s[r]] >= 0) {
                    ++cnt;
                }//比如这个s[r]是a,所以减了以后chars[a] = 3 - 1 = 2。最后如果cnt==t.size说明这一段已经包含了t的所有字符
                while (cnt == t.size()) { // 进入这个while循环的都是已经包含了t中所有的字符,在这里面是选择最短的
                    if (r - l + 1 < min_size) {
                        min_l = l;
                        min_size = r - l + 1;
                    }//算出如果这个时候小于min_size,说明他比之前找到的短,更新左坐标
                    if (flag[s[l]] && ++chars[s[l]] > 0) {//flag[s[l]]是说明这个时候左边这个字符是t中的字符
                        --cnt;//进入这个循环以后,因为你去掉了s中属于t的一个字符,所以cnt不可能和t.size相等,退出while循环,。
                    }
                    ++l;//不管怎么都左移一位左指针
                }
            }
        }

最终代码:

class Solution {
public:
    string minWindow(string s, string t) {
        vector<int> chars(128, 0);
        vector<bool> flag(128, false);
        for (int i = 0; i < t.size(); ++i) {
            flag[t[i]] = true; //判断这个字符是不是在t里面出现过,比如字母a出现了就设置flag[a]为真
            ++chars[t[i]]; //看每一个字母出现了多少次,比如a出现了三次,所以最后chars[a] = 3
        }
        int cnt = 0, l = 0, r = 0, min_l, min_size = s.size() + 1;
        for (r = 0; r < s.size(); ++r) {
            if (flag[s[r]]) {
                if (--chars[s[r]] >= 0) {
                    ++cnt;
                }//比如这个s[r]是a,所以减了以后chars[a] = 3 - 1 = 2。最后如果cnt==t.size说明这一段已经包含了t的所有字符
                while (cnt == t.size()) { // 进入这个while循环的都是已经包含了t中所有的字符,在这里面是选择最短的
                    if (r - l + 1 < min_size) {
                        min_l = l;
                        min_size = r - l + 1;
                    }//算出如果这个时候小于min_size,说明他比之前找到的短,更新左坐标
                    if (flag[s[l]] && ++chars[s[l]] > 0) {//flag[s[l]]是说明这个时候左边这个字符是t中的字符
                        --cnt;//进入这个循环以后,因为你去掉了s中属于t的一个字符,所以cnt不可能和t.size相等,退出while循环,。
                    }
                    ++l;//不管怎么都左移一位左指针
                }
            }
        }
        return min_size > s.size()? "": s.substr(min_l, min_size);//所以前面设置的初值min_size要比s。size大
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

UPC YR

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

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

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

打赏作者

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

抵扣说明:

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

余额充值