【leetcode】【剑指offer Ⅱ】017. 含有所有字符的最短字符串

问题描述:

  • 给定两个字符串 s 和 t,返回 s 中包含 t 的所有字符的最短子字符串。【t 中可能存在重复字符,重复字符的数量也需要得到保证】
    • 如果 s 中不存在符合条件的子字符串,则返回空字符串。
    • 如果 s 中存在多个符合条件的子字符串,返回任意一个。

核心思路:

  • 该题是用滑动窗口思想来解题,简单来说,只需要保持窗口中字符不重复即可(用哈希表记录字符串 t 中字母的频数)。【但想要维护窗口中字符不重复也并非易事】
    • 暴力的方法是在每一次更新窗口时遍历检查哈希表,查看保存的频数是否超过 1
  • 但显然需要更好的思路来优化时间复杂度。
    • 用哈希表记录字符串 t 中字母的频数,确切地来说,初始化哈希表时遍历 t,遇到一个字母,哈希表中对应频数减一
    • 后续遍历字符串 s 的时候就可以在同一个哈希表中进行更新,即在遍历 s 时,遇到一个字母,哈希表中对应频数加一。【由此可以看出,哈希表记录的是窗口中字母与字符串 t 中对应字母的差值
    • 同时用一个变量 cnt 记录字符串 t非重复字母的个数。【cnt 的作用很关键,用它可以判断窗口是否满足条件(条件是窗口包含 t 中所有字符)】
  • cnt 需要和哈希表搭配使用:
    • 当哈希表中某个元素从负数升至 0,则说明窗口中字母与字符串 t 中对应字母的差值变为 0,则计数 cnt 需要减一。
    • 当哈希表中某个元素从 0 降至负数,则说明窗口中字母个数少于字符串 t 中对应字母的个数,则计数 cnt 需要加一。
    • 因此当 cnt = 0 时,窗口满足条件(满足条件就可以减小窗口)。【cnt 不可能降为负值,直观地来说,cnt 记录的就是哈希表中存在多少个负值】

代码实现:

class Solution
{
public:
    string minWindow(string s, string t)
    {
        int m = s.size(), n = t.size();
        if(n > m) return "";
        unordered_map<int, int> a;
        int cnt = 0;
        for(int i = 0; i < n; ++i)
        {
            if(a.count(t[i]) == 0) ++cnt; // 记录t串中有多少个不同的字母
            --a[t[i]];
        }
        int l = 0, r = 0;
        int idx = -1, len = m+1;
        while(r < m)
        {
            if(++a[s[r++]] == 0) --cnt;
            while(l < r and cnt == 0)
            {
                if(r - l < len) idx = l, len = r - l;
                if(a[s[l++]]-- == 0) ++cnt;
            }
        }
        return idx == -1 ? "" : s.substr(idx, len);
    }
};

你可能感兴趣的:(#,剑指,offer,Ⅱ,leetcode)