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


🧠 题目解析

题目描述:

给定两个字符串 sp,找出 s 中所有 p字母异位词的起始索引。

返回的答案以数组形式表示。

字母异位词定义:

若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为字母异位词。

例如:"abc""bca" 是异位词;"aab""aba" 也是。


✅ 解法一:定长滑动窗口 + 计数数组比较

基本思路:

  • 使用两个数组 分别统计 ps 某个长度为 p.length() 的子串的字母频次。
  • 每次滑动窗口右移一位,更新窗口内的字符频次,并比较两个数组是否相等。
  • 若频次完全相同,则说明当前窗口是 p 的一个异位词。

🔍 C++ 实现

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans;
        if (s.length() < p.length()) return ans;

        array<int, 26> cnt_p{}; // 存 p 中每个字母的出现次数
        array<int, 26> cnt_s{}; // 存 s 当前窗口中每个字母的出现次数

        for (char c : p) {
            cnt_p[c - 'a']++;
        }

        for (int i = 0; i < s.length(); ++i) {
            cnt_s[s[i] - 'a']++; // 当前字符进入窗口

            if (i >= p.length()) {
                // 超出窗口长度,移除最左字符
                cnt_s[s[i - p.length()] - 'a']--;
            }

            if (cnt_s == cnt_p) {
                // 当前窗口字符频次与 p 相同,记录左边界
                ans.push_back(i - p.length() + 1);
            }
        }

        return ans;
    }
};

🧮 复杂度分析

  • 时间复杂度: O(n),n 为 s 的长度,数组比较常数级。
  • 空间复杂度: O(1),使用两个长度为 26 的数组。

✅ 解法二:滑动窗口 + 字符差值平衡法

核心思想:

  • 维护一个字符差值数组 cnt[26],初始记录 p 中每个字符出现次数。
  • 当字符进入窗口时,对应计数减一;字符离开时加一。
  • 如果窗口中字符完全匹配,cnt 中所有值为 0。

🔍 C++ 实现

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans;
        if (s.length() < p.length()) return ans;

        int cnt[26] = {0}; // 差值数组

        // 初始化 p 的频次
        for (char c : p) {
            cnt[c - 'a']++;
        }

        int left = 0;
        for (int right = 0; right < s.length(); ++right) {
            int idx = s[right] - 'a';
            cnt[idx]--; // 当前字符进入窗口

            // 如果某个字母用得太多,收缩左边界
            while (cnt[idx] < 0) {
                cnt[s[left] - 'a']++;
                left++;
            }

            // 若窗口长度等于 p 的长度,则说明是异位词
            if (right - left + 1 == p.length()) {
                ans.push_back(left);
            }
        }

        return ans;
    }
};

⚙️ 工作流程示意:

每次移动窗口,都:

  1. 加入一个新字符(右指针);
  2. 若出现次数超出,则移动左指针缩减窗口;
  3. 判断窗口大小是否等于 p.length(),若是且匹配,则记录起始索引。

🔍 为什么用数组而不是 unordered_map?

  • 数组比 unordered_map 更快,因为操作字符时用 char - 'a' 转索引非常高效。
  • 我们仅处理小写字母(a-z),长度固定 26,用数组更节省空间、运行更快。

✨ 总结对比

解法 原理 时间复杂度 空间复杂度 特点
解法一 滑动窗口 + 频次比较 O(n) O(1) 简洁直观
解法二 差值滑动窗口 O(n) O(1) 更快的收缩

相关推荐
快去睡觉~28 分钟前
力扣1005:k次取反后最大化的数组和
数据结构·算法·leetcode
想不明白的过度思考者37 分钟前
初识数据结构——Map和Set:哈希表与二叉搜索树的魔法对决
数据结构·散列表
smilejingwei43 分钟前
数据分析编程第二步: 最简单的数据分析尝试
数据库·算法·数据分析·esprocspl
天意生信云44 分钟前
生信分析自学攻略 | R语言数据筛选和修改
数据结构·经验分享·r语言
月盈缺1 小时前
学习嵌入式第二十三天——数据结构——栈
数据结构·学习
草莓熊Lotso1 小时前
【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day10
c语言·开发语言·经验分享·算法·强化
张同学的IT技术日记2 小时前
详细实例说明+典型案例实现 对迭代法进行全面分析 | C++
算法
Coovally AI模型快速验证2 小时前
全景式综述|多模态目标跟踪全面解析:方法、数据、挑战与未来
人工智能·深度学习·算法·机器学习·计算机视觉·目标跟踪·无人机
草莓熊Lotso3 小时前
【C++】--函数参数传递:传值与传引用的深度解析
c语言·开发语言·c++·其他·算法
不知名。。。。。。。。3 小时前
算法 ----- 链式
算法