【Hot 100 刷题计划】 LeetCode 438. 找到字符串中所有字母异位词 | C++ 滑动窗口题解

LeetCode 438. 找到字符串中所有字母异位词 | C++ 固定滑动窗口极致优化题解

📌 题目描述

题目级别:中等

给定两个字符串 sp,找到 s 中所有 p异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

  • 异位词 :指由相同字母重排列形成的字符串(包括相同的字符串)。换句话说,异位词就是字符种类相同,且每种字符出现次数也相同的字符串。

  • 示例 1:

    输入: s = "cbaebabacd", p = "abc"

    输出: [0,6]

    解释:

    起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。

    起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。


💡 解题思路:固定长度的滑动窗口

寻找连续的子串,必然用到滑动窗口

由于异位词的一个重要前提是长度必须相等 ,所以我们不需要像通常的滑动窗口那样频繁地收缩和扩张,这道题的窗口大小是固定 的,恒等于 p.size()

核心步骤:

  1. 频次统计:我们要判断两个字符串是否互为异位词,只需要判断它们包含的字符频次是否完全一致。
  2. 初始化窗口 :先统计字符串 p 的字符频次,并在字符串 s 中框出前 p.size() 个字符,统计这个初始窗口的字符频次。如果两者相等,就把索引 0 加入结果集。
  3. 整体平移 :窗口开始向右滑动。每次滑动,实际上就是**"吃进"一个右边的新字符,同时"吐出"**一个左边的旧字符。
  4. 状态比对 :每次滑动后,比对当前窗口的频次和 p 的频次是否相同,如果相同,就记录当前窗口的起始索引。

🚀 性能优化杀手锏:数组代替哈希表

在判断频次时,普通哈希表(unordered_map)有较大的常数级时间开销。

由于题目限定了只包含 26 个小写英文字母 ,我们完全可以使用 vector<int>(26, 0) 或者单纯的整型数组来代替哈希表。在 C++ 中,vector 也是重载了 == 运算符的,可以直接比较两个 vector 是否完全一致!


💻 C++ 代码实现 (数组哈希优化版)

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> res;
        int m = s.size(), n = p.size();
        
        // 长度不够,直接返回空
        if (m < n) return res;

        // 使用长度为 26 的 vector 代替哈希表,性能极高
        vector<int> p_cnt(26, 0);
        vector<int> win_cnt(26, 0);

        // 1. 初始化目标字符串 p 的频次,以及 s 中第一个窗口的频次
        for (int i = 0; i < n; i++) {
            p_cnt[p[i] - 'a']++;
            win_cnt[s[i] - 'a']++;
        }

        // 判断第一个窗口是否符合条件
        if (p_cnt == win_cnt) {
            res.push_back(0);
        }

        // 2. 窗口开始整体向右平移
        // i 指向即将移入窗口的右侧新字符
        for (int i = n; i < m; i++) {
            // 右边吃进一个新字符
            win_cnt[s[i] - 'a']++;
            // 左边吐出一个旧字符 (i - n 是滑出窗口的那个字符的索引)
            win_cnt[s[i - n] - 'a']--;

            // 直接比较两个 vector 是否完全一致
            if (p_cnt == win_cnt) {
                // i 是窗口右边界,减去长度 n 再加 1,就是窗口的起始索引
                res.push_back(i - n + 1);
            }
        }

        return res;
    }
};
相关推荐
weilx12341 分钟前
C++笔记-mutex
c++
beijixinghe11 分钟前
第15节 指针作为函数参数的工程实战用法
开发语言·c++·c++基础·c++入门·几何引擎c++
一起努力啊~16 分钟前
算法题打卡力扣第1658题:将 x 减到 0 的最小操作数(mid)
学习·leetcode
j7~26 分钟前
【C++微服务项目开发脚手架】(准备篇)从 0 到跑通:Docker 容器开发环境 + 宿主机用户 + Trae 远程连接 全链路踩坑实战
linux·c++·学习·xshell·docker容器·trae
和裕27 分钟前
平口开槽箱 vs 飞机盒 vs 扣底盒:自动化、展示效果与成本核心区别
大数据·运维·网络·人工智能·算法·自动化
AgentMaster33 分钟前
从售前到售后全链路覆盖:智能客服在企业 5 大场景的落地实践与工具选型
大数据·人工智能·算法
Cccp.12335 分钟前
【leetcode】(六) 图和贪心算法
数据结构·算法·leetcode
y1su37 分钟前
【Leetcode】1477. 找两个和为目标值且不重叠的子数组
数据结构·后端·算法·leetcode·职场和发展
唠玖馆44 分钟前
C++11
c++
云泽8083 小时前
从零搭建 WSL2 + Ubuntu C/C++ 开发环境:原理、实践与底层架构解析
linux·c++·windows·ubuntu·wsl2