LeetCode.438. 找到字符串中所有字母异位词

52 阅读2分钟

题目

image.png

思路

  • 滑动窗口,窗口内维护所需要的字符,在所需要的字符都满足后,因为我们需要的是窗口的左端点,所以此时尽可能收缩左端点,把不合法的字符排除掉的
  • 为了实时知道我们还需要哪些字符,以及什么时候,窗口已然包含了我们所需的所有字符了,可以用一个计数数组need[]来记录窗口内字符的情况

代码

vector<int> findAnagrams(string s, string p) 
{
    auto n = s.size();
    auto m = p.size();
    vector<int> ans;
    
    int needCnt = m;//记录需要的字符数量
    vector<int> need(123,0);//记录需要那哪些字符,小写字符z Ascii=122
    //need['a'] = 1
    //need['b'] = 1
    //need['c'] = 1
    //need[x] > 0: 需要字符x,数值=需要该字符的数量
    //need[x] < 0: 字符x多余

    for(const char& c:p)
    {
        need[c]++;
    }

    int L = 0;
    int R = 0;
    while(R < n)
    {
        char c = s[R];
        R++;
        if(need[c] > 0)//若是目标字符,则还需要的字符数--
        {
            needCnt--;
        }
        need[c]--;
        if(needCnt == 0)//所有需要的字符都有了,收缩左窗口,看有没有多余的字符(need[x]<0)
        {
            while(L < R && need[s[L]] < 0)//s[L]是多余的,可以收缩窗口
            {
                need[s[L]]++;
                L++;
            }
            if(R-L == m)//因为L...R中间可能存在多余的字符,这种情况左端点收缩也没办法把这些多余的排除,所以必须这样判断筛选合法的答案
            {
                ans.push_back(L);
            }

        }
    }
    return ans;
}

总结

  • 需要找一个包含指定多个字符的连续子串,可以用滑动窗口解决,期望窗口内部就包含所有需要的字符。窗口右端点R去寻找字符,左端点适时收缩以排除不需要的字符,整体目标是维护窗口内的字符都是所需要的
  • 为了知道窗口内部的字符情况,比如哪些是多余的,哪些是需要的,可以用计数数组need[],滑动窗口左右端点更新的时候,计数数组同步更新
  • 上面代码还是可以改进的,或者说,有另一种方法。在第一次找到合法L后,cnt=0,而没有重置,意味着后续的合法L,其实都只能通过收缩左端点L找到