hot100_找到字符串中所有字母异位词

分析

要找到p的所有字母异位词,其实是找到字符串p里各种字母的组合。那么我们可以通过维护len(p)长度的窗口来判断是否是p的字母异位词。


题解

滑动窗口

固定长度滑动窗口,窗口大小等于p.size()

  1. 用两个大小26的数组,分别统计p、s窗口内每个字母出现次数;
  2. 数组完全相等 = 窗口内字符是p的字符异位词;
  3. 每次窗口右移一格:左边出去一个字符计数减一,右边进来一个字符计数加一。

代码

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int sLen = s.size(), pLen = p.size();
        if(sLen < pLen) return {};
        vector<int> ans;
        vector<int> sCount(26);
        vector<int> pCount(26);
        for(int i = 0; i < pLen; i++) {
            pCount[p[i] - 'a']++;
            sCount[s[i] - 'a']++;
        }
        if(sCount == pCount) ans.emplace_back(0);
        for(int i = 0; i < sLen - pLen; i++) {
            sCount[s[i] - 'a']--;
            sCount[s[i + pLen] - 'a']++;
            if(sCount == pCount) {
                ans.emplace_back(i + 1);
            }
        }
        return ans;
    }
};
  • 时间复杂度: O ( n ) O(n) O(n),n为s长度,数组比较是固定26次,属于常数开销
  • 空间复杂度: O ( 1 ) O(1) O(1),两个26大小数组,与输入规模无关

优化的滑动窗口

核心思想:只用一个 cnt[26] 数组

  • p的字符:cnt++
  • s窗口内字符:cnt--

如果窗口是p的异位词,则全部 26 个位置cnt[i] = 0;

diff记录不等于 0 的字母个数,diff == 0代表窗口匹配成功。

代码

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int sLen = s.size(), pLen = p.size();
        if(sLen < pLen) return {};
        vector<int> cnt(26,0);
        vector<int> ans;
        for(int i = 0; i < pLen; i++){
            cnt[p[i]-'a']++;
            cnt[s[i]-'a']--;
        }
        int diff = 0;
        for(int x: cnt) if(x!=0) diff++;
        if(diff == 0) ans.push_back(0);
        for(int i = 0; i < sLen - pLen; i++){
            int out = s[i]-'a';
			// 移动之前,如果cnt[out]==0:说明这个字母之前两边完全相等 
			// 现在要修改它,相等状态被破坏,diff+1
            if(cnt[out] == 0) diff++;
            cnt[out]++;   // s窗口去掉这个字符,所以差值数组+1
			// 修改完之后,如果cnt[out]==0:现在两边又相等了,diff‑1
            if(cnt[out] == 0) diff--;
            int in = s[i + pLen]-'a';
			// 修改前等于0,原本相等,即将被破坏,diff++
            if(cnt[in] == 0) diff++;   
            cnt[in]--;    // s窗口新增该字符,差值数组-1
			// 修改后等于0,该字母计数达成一致,diff--
            if(cnt[in] == 0) diff--;
			// diff=0,全部字母计数匹配,窗口起始位置 i+1
            if(diff == 0) ans.push_back(i+1);
        }
        return ans;
    }  
};
  • 时间复杂度: O ( n + m ) O(n + m) O(n+m),n是s长度,m是p长度;不再每次循环比较26个 vector 元素
  • 空间复杂度: O ( 1 ) O(1) O(1),固定大小 26 数组。

对比原始双 vector 写法:原始写法每次if(sCount == pCount)底层会循环比较 26 次,虽然是常数,但 diff 版本把 26 次比较消除,效率更高。

438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值