LeetCode第76题(最小覆盖子串)

原题如下:

给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。

示例:

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

如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。

说实话,这道题如果以前没有做过类似的题目,写起来相当吃力,总是时间复杂度太高!!
最简单粗暴的方法就是 从t.size()开始依次大1个size 截取 s的子串 看其是否覆盖了t 如果是则直接返回 否则 再截取 以此类推。

然而简单的方法。。。时间复杂度多半比较高。。。
之后又想了好几种方法,(但是始终都是双 层 遍历),即使我用了很多break 语句,打破了很多循环,但是依旧不理想。。。(这时候你就要去想一想,有没有多余的遍历!需要双层遍历。。。既然时间复杂度比较高,那么我们肯定做了很多无用功!!!(其他题如果时间复杂度比较高也是如此))

最后,果然发现 其实只用遍历一遍就行了,因为当第一次从start 开始遍历到 end
(end 位置的时候 刚好覆盖t)那么下次 开始的时候 start 一定 是从 s中 start之后 第一个 在t中存在的 位置 设为new_start 而end 呢?我们有必要 从 start 开始吗?(想一想?)
我们只需要 从当下end 开始即可(new_start到当前的end 有可能仍然覆盖t 所以我为了方便 每次都把 end减了1 这时候 new_start 到new_end(end-1) 必然不会覆盖 t 下次循环 end 就从 new_end+1 开始(也就是上次覆盖子串的末尾部分) )
这时候 就遇到问题了 下一次循环的时候 end 直接就从上次的末尾开始了 (我怎么知道 新的一轮循环 end 到哪儿 截至???) 这时候 我们 需要 一个 int变量(比如count吧)记录 当前 start 到 end 位置中 s 已经覆盖了 t 多少个字符(当 count==t.size()的时候 不就是覆盖了?)
紧接着 又遇到问题了 因为s的串是非常长的 有时候 有可能 其中一个字符 已经大于 t中的相应字符的个数了(比如 子串 “bbac” 和 t=“bac”) 遇到第二个b 我们是不能 让 count++的 (因为t中的‘b’只有一个)(我们就需要知道b当前状况下出现了几次????)

所以情况就很明朗了 我们 需要 用数组 记录 t中 每个 字符 的个数
用 另外 一个数组 记录 当前start 到end (注意不是0—>end 下面也是一样)的 每个字符的个数(起始全是0 ,多了也要统计上)
用count 去记录 start—–>end 中覆盖t 的字符个数 (ps:你需要注意什么时候count++ (end位置上的字符对应的数组(s_hash[])中元素 是一定要加1 ,但是count+1是取决于 该字符 在t中是否达到饱和)什么时候 count – ?我们去找new_start的时候是同样的道理 )

比起上来直接说,要用hash表,要用count去计数,我更喜欢一点一点引入,为什么要这样用 ,如果你把上面的看懂了,其实下面的代码就不用看了

typedef struct MyStruct
{
    int front;
    int back;
    MyStruct() :front(-1), back(-1){}
 }MyStruct;
class Solution {
public:
vector<int> get_hash(string s){
        vector<int>m(58); for (int i = 0; i <= 57; i++)m[i] = 0;
        for (int i = 0; i <= s.size() - 1; i++) m[s[i] - 'A']++;
        return m;
    }
    string  minWindow(string s, string t){
        string str; 
        int count = 0;
        MyStruct min;
        if (t.size() == 0 || s.size() == 0 || s.size() < t.size())return str;
        vector<int> t_hash = get_hash(t);
        int s_hash[58] = {0};
        int start = 0,end=0;
            for (end=0; end <= s.size() - 1; end++){
                int i = s[end] - 'A';
                if (t_hash[i] == 0) continue;
                s_hash[i]++;//注意这个写的位置 没有判断条件
                if (s_hash[i] <= t_hash[i]) count++;//注意这个写的位置 带等号!!!!
                if (count == t.size()){
                    if (min.front == -1 || end - start + 1 < min.back - min.front + 1)
                    {  min.front=start;min.back=end ;}
                    i = s[start] - 'A'; 
                    if(s_hash[i]>0) s_hash[i]--; 
                    if(s_hash[i]<t_hash[i]) count--;//注意这个
                    int j = start + 1;
                    if (j >= s.size()) break;
                    while (j <= end){
                        if (t_hash[s[j] - 'A'] != 0)break;
                        else j++;
                     }
                    start = j; 
                    if (s_hash[s[end] - 'A'] > 0) { s_hash[s[end] - 'A']--; count--; end--; }
                }
            }//end wai for
        if (min.front != -1) str = s.substr(min.front, min.back - min.front + 1);
        return str;
    }
    };

猜你喜欢

转载自blog.csdn.net/qq_42203013/article/details/82696560