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

目录

题目描述

示例1:

示例2:

提示:

解题思路

Collections库

介绍

滑动窗口法

概念

应用场景及特点:

思路

流程展示

代码

复杂度分析


题目描述

给定两个字符串sp,找到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 * (10**4)
  • sp 仅包含小写字母

解题思路

Collections库

介绍

Python的collections库是一个内建模块,它提供了一系列特殊的容器数据类型,用于扩展Python的标准内建容器(如字典、列表、集合和元组)。这些特殊的容器类型提供了比通用数据类型更多的选择和更好的性能,非常适合在需要高效数据处理和复杂数据结构时使用。

滑动窗口法

概念

滑动窗口是一个在序列上移动的区间,通常由左右两个指针来界定这个区间的范围。通过移动指针来改变窗口的大小和位置,在窗口移动的过程中,根据问题的需求进行特定的计算和处理。

应用场景及特点

  1. 子数组 / 子串问题
  • 当需要在一个序列中找到满足特定条件的连续子数组或子串时,滑动窗口非常适用。例如,寻找和为特定值的连续子数组、含有特定字符的最长子串等。
  • 窗口的大小通常是动态变化的,根据问题的条件进行调整。
  1. 高效性
  • 相比于暴力枚举所有可能的子数组 / 子串,滑动窗口法通常能够在更短的时间内找到解。因为它利用了子数组 / 子串的连续性和窗口的滑动特性,避免了重复计算。
  1. 指针移动规则
  • 通常有两个指针,一个指向窗口的左端,一个指向窗口的右端。根据问题的具体要求,以特定的方式移动指针。
  • 例如,在寻找满足特定条件的最小子数组时,可能会先扩大窗口直到满足条件,然后再缩小窗口以找到最小的满足条件的窗口。

思路

这道题可以使用滑动窗口(Sliding Window)和哈希表的结合来解决。解题的关键是如何有效地在字符串 s 中找到与字符串 p 的异位词相同的子串。

  1. 异位词特征:两个字符串是异位词,那么它们每个字符的出现次数是相同的。因此,我们可以使用字符频率来判断一个子串是否是异位词。
  2. 滑动窗口 :我们在字符串 s 上维护一个大小为 len(p) 的滑动窗口,记录窗口内的字符频率。当窗口的大小等于 p 的长度时,我们检查窗口内的字符频率是否和 p 的字符频率相同。如果相同,则说明当前窗口是 p 的一个异位词,我们记录下窗口的起始索引。
  3. 窗口滑动:每次窗口滑动时,我们更新窗口的字符频率,移出窗口左边的一个字符,并添加右边新进入窗口的字符。

流程展示

代码

python 复制代码
class Solution:  
    def findAnagrams(self, s: str, p: str) -> List[int]:  
        res = []
        n, m = len(s), len(p)
        if n < m:
            return res
        
        # 初始化p的字符频率
        p_count = collections.Counter(p)
        # 初始化窗口的字符频率
        window = collections.Counter(s[:m-1])
        
        for i in range(m-1, n):
            # 增加新的字符到窗口
            window[s[i]] += 1
            # 如果窗口字符频率和p字符频率相同,记录起始索引
            if window == p_count:
                res.append(i - m + 1)
            # 移除左边的字符,保持窗口大小为m
            window[s[i - m + 1]] -= 1
            if window[s[i - m + 1]] == 0:
                del window[s[i - m + 1]]
        
        return res

复杂度分析

  • 时间复杂度O(n),其中 n 是字符串 s 的长度。遍历字符串 s 需要 O(n) 时间,在每次窗口移动时,我们对窗口内的字符进行更新和比较,哈希表的比较是 O(1),因此总时间复杂度是 O(n)
  • 空间复杂度O(m),其中 m 是字符串 p 的长度。我们使用了两个哈希表来存储字符频率,每个哈希表最多存储 m 个不同的字符,因此空间复杂度是 O(m)
相关推荐
小码农<^_^>37 分钟前
优选算法精品课--滑动窗口算法(一)
算法
羊小猪~~39 分钟前
神经网络基础--什么是正向传播??什么是方向传播??
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
软工菜鸡1 小时前
预训练语言模型BERT——PaddleNLP中的预训练模型
大数据·人工智能·深度学习·算法·语言模型·自然语言处理·bert
南宫生1 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
AI视觉网奇2 小时前
sklearn 安装使用笔记
人工智能·算法·sklearn
JingHongB2 小时前
代码随想录算法训练营Day55 | 图论理论基础、深度优先搜索理论基础、卡玛网 98.所有可达路径、797. 所有可能的路径、广度优先搜索理论基础
算法·深度优先·图论
weixin_432702262 小时前
代码随想录算法训练营第五十五天|图论理论基础
数据结构·python·算法·深度优先·图论
小冉在学习2 小时前
day52 图论章节刷题Part04(110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长 )
算法·深度优先·图论
Repeat7152 小时前
图论基础--孤岛系列
算法·深度优先·广度优先·图论基础
小冉在学习2 小时前
day53 图论章节刷题Part05(并查集理论基础、寻找存在的路径)
java·算法·图论