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

文章描述了一种使用滑动窗口优化算法来寻找字符串中最短包含给定字符集合的子串的方法。通过哈希表存储字符出现次数,遍历字符串,动态调整窗口大小,以达到最短长度。在处理重复字符和剔除无用元素时,左指针的移动策略是关键。
摘要由CSDN通过智能技术生成

在这里插入图片描述
思路:
    本题的是要求最短字串,由于这种特殊性,我们势必要考虑遍历所有元素来求得最短子串,那么一般这个时候会使用滑动窗口来优化。本题的滑动窗口的思路和普通的窗口是不同的,但是本质上都是符合一定条件的情况下移动右指针,或者左指针。本题的步骤如下:
(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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值