剑指 Offer II 017. 含有所有字符的最短字符串

剑指 Offer II 017. 含有所有字符的最短字符串_第1张图片
思路:
    本题的是要求最短字串,由于这种特殊性,我们势必要考虑遍历所有元素来求得最短子串,那么一般这个时候会使用滑动窗口来优化。本题的滑动窗口的思路和普通的窗口是不同的,但是本质上都是符合一定条件的情况下移动右指针,或者左指针。本题的步骤如下:
(1)起始两个指针都指向第一个元素,移动右指针,直到子串的所有字符都出现。
(2)移动右指针剔除无用元素和重复元素。
(3)寻找临界点,计算长度。

(1)因为之后要进行字符串的比较来判断子串元素是否出现,所以考虑使用哈希表对短串的字符进行储存。用字符当key,出现就把value+1。

int n = s.size(), m = t.size();
unordered_map<char, int>mp;
for (auto& ch : t)
    mp[ch]++;

    如何判断是否所有字符都出现呢,因为我们有短串的字符长度,所以我可以用长度作为变量来统计是否所有字符都出现,也就是说出现一次,长度-1,这样当长度为0的时候,表示所有字符都出现了。当然为了避免重复字符消耗长度次数,要结合哈希表来进行处理。如果,”A“这个字符第一次出现的时候,对应哈希表的值为1,当值大于0的时候表示该字符第一次出现,就可以把值变为0,同时长度-1。下次再遇到"A"的时候,值不为0也就不再减少次数了。当然都是在for循环中实现的。

if (mp.count(s[i])) {
    if (mp[s[i]] > 0)
        mp[s[i]]--, m--;
    else 
        mp[s[i]]--;

(2)当所有字符都出现后,为了避免有重复字符,同时为了寻求到字段子串必然要剔除一些无用字符。我们需要分情况进行处理,但是总的来说都是对左指针进行右移来实现的。
    启动条件是m==0也就是出现所有字符后。
    首先我们要知道对应的哈希表里面只可能有2种情况,①值为0,代表这一个子串中,该元素只出现了一次②值不为0,代表该元素重复出现了。
    所以我们依次对左指针的元素判断时就有以下几种情况①这个字符在子串没出现过,所以在哈希表中也没有这个字符,那么直接左指针移动就可以了。②如果对应这个值为0就代表如果我再移动,剩下的子串就不包含这个字符了,也就是不再是符合要求的子串了,这个时候就可以计算长度了。②其他情况,这里就对应该字符是重复字符,对应的哈希表的值必须++,然后再右移。
    在计算长度的时候,同时记录长度和左起第一个字符的位置,这样最后返回的时候就能打印出中间的字符串了。

while (m == 0) { // 始终满足条件一:包含子串
    if (!mp.count(s[st])) {
        st++;
        continue;
    }
    if (mp[s[st]] == 0) { // 临界点
        if (i - st + 1 < len) { // 找到更小的就更新答案
            ans = st;
            len = i - st + 1;
        }
        break;
    }
    else { // 多余字符可以缩短长度,st++
        mp[s[st]]++;
        st++;
    }

    以下用来处理空字符串和返回结果。

if (len == 1e6) return "";
return s.substr(ans, len);

你可能感兴趣的:(c++,数据结构,算法)