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

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

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

示例 1:

输入: s = "cbaebabacd", p = "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

 示例 2:

输入: s = "abab", p = "ab" 输出: [0,1,2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

提示:

  • 1 <= s.length, p.length <= 3 * 104
  • s 和 p 仅包含小写字母

核心方法:固定长度滑动窗口 + 数组计数抵消(替代字典,效率更高)

核心逻辑梳理

  1. 异位词的本质:子串与 p字符种类完全相同、每种字符的出现次数完全相同(顺序无关),因此子串长度必须等于 p 的长度(这是前提,窗口长度固定为 len(p))。
  2. 计数抵消的核心
    • 先统计 p 中所有字符的出现次数,将其存入计数数组并设为「负值」(相当于「需要抵消的目标」)。
    • 再用滑动窗口遍历 s,窗口内的字符计数「加 1」,当计数数组所有值都归 0 时,说明窗口内字符与 p 完全匹配(异位词)。
  3. 固定窗口滑动规则
    • 初始化第一个窗口(s 的前 len(p) 个字符),完成初始计数抵消。
    • 后续窗口整体向右滑动,移除窗口左侧离开的字符(计数减 1)、添加窗口右侧新增的字符(计数加 1),无需重新统计整个窗口,保证效率。
  4. 优化点:用长度为 26 的数组(对应 26 个小写英文字母)替代字典,避免 KeyError,且数组访问 / 比较效率更高,是本题的最优选择(时间复杂度 O (n),空间复杂度 O (1))。
  5. 边界处理:若 s 长度小于 p 长度,直接返回空列表(无有效子串)。

思路落地关键补充

  • 你想的「全 0 时记录 left」完全正确,数组格式下直接用 count == [0] * 26 即可快速判断。
  • 遇到不属于 p 的字符时,无需额外跳转(数组天然只统计 26 个字母,且窗口固定长度,滑动时会自动清除无效字符的计数影响),简化逻辑。

from typing import List

class Solution:

    def findAnagrams(self, s: str, p: str) -> List[int]:

        result = []

        s_len = len(s)

        p_len = len(p)

       

        # 边界条件:如果 s 长度小于 p 长度,直接返回空列表

        if s_len < p_len:

            return result

       

        # 初始化 26 个小写英文字母的计数数组(对应 a-z)

        count = [0] * 26

       

        # 步骤 1:统计 p 的字符,设为负值(贴合你的计数抵消思路)

        for c in p:

            idx = ord(c) - ord('a')

            count[idx] -= 1

       

        # 步骤 2:初始化第一个窗口(s 的前 p_len 个字符),计数累加抵消

        for i in range(p_len):

            idx = ord(s[i]) - ord('a')

            count[idx] += 1

       

        # 步骤 3:滑动窗口遍历所有可能的起始位置

        for i in range(s_len - p_len + 1):

            # 修正错误 1:数组和全 0 数组比较(正确判断计数是否全 0)

            if count == [0] * 26:

                result.append(i)

           

            # 边界条件:如果是最后一个窗口,无需滑动(避免索引越界)

            if i == s_len - p_len:

                break

           

            # 步骤 4:滑动窗口:移除左侧字符,添加右侧新字符

            # 移除当前窗口的左侧字符 s[i]

            left_char_idx = ord(s[i]) - ord('a')

            count[left_char_idx] -= 1

           

            # 修正错误 2:添加下一个窗口的右侧字符 s[i+p_len](而非 i+p_len-1)

            right_char_idx = ord(s[i + p_len]) - ord('a')

            count[right_char_idx] += 1

       

        return result

Read more

Node.js 下载安装与环境配置全流程(保姆级详解)| 图文详解,快速上手

Node.js 下载安装与环境配置全流程(保姆级详解)| 图文详解,快速上手

前言 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。它采用事件驱动、非阻塞式 I/O 模型,使得其在处理高并发任务时具有极高的效率。得益于这样的设计,Node.js 在 Web 开发、实时应用、微服务架构等场景中被广泛使用。 除了高性能,Node.js 还配备了功能强大的包管理器 npm(Node Package Manager)。npm 提供了丰富的开源库和工具,开发者可以轻松地安装、管理和共享代码,使开发过程更加高效。 一、下载安装 Node.js 1.下载安装包: * 访问 Node.js 官方下载页面。 通常页面会显示两个版本: 1. 长期维护版本(推荐)

By Ne0inhk
深度解析个人AI助手OpenClaw:从消息处理到定时任务的全流程架构

深度解析个人AI助手OpenClaw:从消息处理到定时任务的全流程架构

在人工智能快速普及的当下,个人AI助手已经逐渐渗透到我们的工作和生活中,它们能够跨平台接收消息、智能处理需求、执行指定任务,成为提升效率的重要工具。OpenClaw作为一款功能强大的个人AI助手,凭借其灵活的渠道适配、完善的路由机制、强大的Agent能力以及可靠的定时任务系统,在众多AI助手中脱颖而出。很多开发者在使用OpenClaw时,都会好奇其背后的运行逻辑:当我们在WhatsApp、Discord等平台发送消息时,OpenClaw是如何捕捉到这些消息的,又是如何一步步处理并给出回复的;Web UI端的消息传递和外部渠道有何不同;Pi Agent如何调用大语言模型(LLM)和执行本地命令;定时任务从创建到结束的完整生命周期又包含哪些环节。今天,我们就结合OpenClaw的源代码,对这些核心功能模块进行全面且深入的解析,带你走进这款个人AI助手的底层架构,读懂每一个流程背后的技术实现。 OpenClaw的整体架构遵循“模块化设计、统一化管理”的理念,无论是消息处理、Agent执行还是定时任务,都有清晰的模块划分和明确的流程逻辑,这不仅保证了系统的稳定性和可扩展性,也让开发者能够快速

By Ne0inhk
什么是约定优于配置?自动配置的原理是什么?一文搞懂SpringBoot底层启动流程

什么是约定优于配置?自动配置的原理是什么?一文搞懂SpringBoot底层启动流程

👨‍💻程序员三明治:个人主页 🔥 个人专栏: 《设计模式精解》《重学数据结构》 🤞先做到 再看见! 目录 * 什么是自动配置类? * 自动配置原理 * 有没有自动配置的区别在哪? * Spring整合Mybatis * 在pom.xml文件中添加jar包的依赖 * 配置MyBatis文件 * 新建一个实体类的包和User实体类 * 编写实体类 * 新建Mapper接口包和UserMapper接口 * resouces下新建jdbc资源文件 jdbc-config.properties * resources下新建mybatis配置文件 mybatis.xml * resources下新建logj4j的日志配置文件log4j.properties * 新建User的映射mapper文件 * 在UserMapper接口中编写映射文件对应的方法 * 配置Spring文件 * resources下新

By Ne0inhk
Flutter 组件 graphql 的适配 鸿蒙Harmony 实战 - 驾驭标准化分布式图形协议、实现鸿蒙端实时订阅与高性能交互网关方案

Flutter 组件 graphql 的适配 鸿蒙Harmony 实战 - 驾驭标准化分布式图形协议、实现鸿蒙端实时订阅与高性能交互网关方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 graphql 的适配 鸿蒙Harmony 实战 - 驾驭标准化分布式图形协议、实现鸿蒙端实时订阅与高性能交互网关方案 前言 在鸿蒙(OpenHarmony)生态的万物互联、极繁交互中台、以及对数据获取灵活性有极致要求的现代应用研发中,“高效的数据检索协议”是应用响应速度的灵魂。面对复杂的社交网络关系查询、实时的行情推送、或是海量状态信息的聚合。如果仅仅依靠传统的 RESTful 接口,那么不仅会导致因为 Over-fetching(获取多余数据)导致的带宽浪费,更会因为频繁的 API 版本演进引入严重的跨端兼容性碎片化问题。 我们需要一种“按需检索、逻辑解耦”的交互艺术。 graphql 是一套专为 Flutter 设计的标准 GraphQL 客户端套件。它通过构建规范的规范化缓存(Normalized Cache)与极其灵活的连接链路(Links)

By Ne0inhk