【打卡】牛客网:BM90 最小覆盖子串

题目:

BM65 最长公共子序列(二):

        找二者的相同部分,该部分对于二者可以不连续排列的(但是是有序的)。

BM66 最长公共子串

        找二者的相同部分,该部分对于二者是连续排列的。

本题:BM90 最小覆盖子串

        找s中包含t所有字符的部分,该部分对于s是连续排列的,对于t可以不连续排列(且可以没有顺序)。

模板的:

编程思想:采用滑动窗口法

  1. 窗口有左右两个指针。
  2. 找到一个符合条件(指包含t所有字符)的子串。
    1. 固定左指针,右指针往右走,
  3. 缩小窗口,找到最小字串。
    1. 固定右指针,左指针往左走。
    2. 记录最小的最小字串。
  4. 重复2和3,直到右指针走完。

编程细节:

  1. hash函数存储
    1. hash.count(c) 表示计算hash表的key中有多少c。常用于查找hash表的key是否存在。hash.count 与 hash[]的区别,什么时候用.count,什么时候用hash[]?_hash_count-CSDN博客
    2. hash表的遍历:for(auto i = hash.begin(); i != hash.end(); i++){}
      1. 此时,key为i->first,slot为i->second
  2. 考虑一些特殊用例:
    1. ​​​​​​​“abc”,"a",返回"a"
      1. ​​​​​​​在while循环中,可能窗口的左指针在右指针的右边,但是因为不满足条件,很快右指针就往右走了。
    2. "a","aa",返回""
      1. 如果hash表在进行初始化时,key=t的每个元素,slot=0;更新hash表时,出现t的元素便加一;判断是否满足条件时,判断hash表的所有key的slot是等于0(不满足条件)还是大于0(满足条件)。这种做法的特点是,对t进行去重处理了。即返回"a"。
      2. 如果hash表在进行初始化时,key=t的每个元素,slot=t的每个元素出现次数的负数;更新hash表时,出现t的元素便加一;判断是否满足条件时,判断hash表的所有key的slot是小于0(不满足条件)还是等于0(满足条件)。这种做法的特点是,在hash表初始化时便记录了t重复元素的个数。即返回""。
  3. 对字符串进行截取,比如,对str的[left,right]截取:
    1. return str.substr(left, right-left+1);
    2. return string(str.begin()+left, str.begin()+right+1);

​​​​​​​​​​​​​​​​​​​​​题目要求时间复杂度是o(n),但是感觉模板的时间复杂度是o(n^2)。因为窗口在s上滑动时,要遍历所有t,判断窗口内是否包含t的全部元素。

#include 
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param S string字符串 
     * @param T string字符串 
     * @return string字符串
     */
    bool check(unordered_map &hash){
        for(auto i = hash.begin(); i != hash.end(); i++){
            if(i->second < 0)
                return false;
        }
        return true;
    }
    string minWindow(string S, string T) {
        // write code here
        int n1 = S.size();
        int n2 = T.size();
        if(n1 == 0 || n2 == 0)
            return "";

        //用hash表来判断是否包含t的元素,对hash表进行初始化
        unordered_map hash;
        for(int i = 0; i < n2; i++){
            hash[T[i]] --; //易错,初始化不用0,而用t元素个数的负数。
        }

        //用于记录
        int ans_r = -1;
        int ans_l = -1;
        int ans_cnt = n1;

        //指针,用于移动
        int p_r = 0;
        int p_l = 0;

        for(; p_r < n1; p_r++){
            //右指针每次往右,都要更新hash表。
            if(hash.count(S[p_r]))
                hash[S[p_r]] ++;

            //满足条件
            while(check(hash)){
                //记录
                if(ans_cnt >= p_r - p_l + 1){
                    ans_cnt = p_r - p_l + 1;
                    ans_r = p_r;
                    ans_l = p_l;
                }

                //满足条件的前提下,缩小窗口,hash表也要更新。
                if(hash.count(S[p_l]))
                    hash[S[p_l]] --;
                p_l ++;
            }
        }
        if(ans_l == -1) //粗心,忘记写
            return ""; 
    
        return S.substr(ans_l, ans_r-ans_l+1);
    }
};

你可能感兴趣的:(算法)