438 找到字符串中所有字母异位词(哈希表、双指针)

43 篇文章 0 订阅

1. 问题描述:

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序。

示例 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" 的字母异位词。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string

2. 思路分析:

这道题目属于经典的双指针算法题目,分析题目可以知道字母异位词需要满足两个条件:

  • 子串长度子字符串p的长度是相等的
  • 子串的字母出现的次数与字符串p出现的字符次数是相等的

所以我们使用两个指针来维护长度为k的区间,k为字符串p的长度,这样可以满足第一个条件,对于第二个条件我们其实是可以使用哈希表来解决的,一开始的时候将字符串p出现的字符次数存储到哈希表中,我们在维护长度为k的区间的时候更新哈希表,如果当前的字符在哈希表中存在那么哈希表中对应的字符数减1,说明当前这种字符需要匹配的字符数目减1,如果某种字符数减为0之后说明当前种类的字符数目满足要求了(这里使用到的一个技巧就是使用一个变量satisfy来记录满足要求的字符种类数目),所以我们在维护长度为k的区间的时候结合哈希表记录一下当前满足字符串p的种类数目satisfy,如果当前的区间长度大于了k之后那么就需要将指针j往右移动,使得区间的长度减小,也即删除掉区间最左边的字符,如果最左边的字符在哈希表中的次数为0说明删除掉当前字符之后满足要求的字母种类是减1的,并且需要更新哈希表中当前字符的匹配数目,也即相应的字符次数要加1,表示当前匹配的字符次数需要多一个。整个过程就是维护长度为k的区间的过程,维护的时候更新哈希表和记录当前匹配的字母种类的变量值,只有当哈希表中所有字符次数减为0而且满足要求的字母种类数目staisfy等于哈希表大小的时候说明满足一种字母异位词。

3. 代码如下:

from typing import List

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        dic = dict()
        # 将字母出现的次数存储到字典中, 表示字母异位词必须满足字母出现的次数
        for c in p:
            if c in dic:
                dic[c] += 1
            else:
                dic[c] = 1
        n = len(s)
        i, j = 0, 0
        staisfy = 0
        res = list()
        # 其实每一次维护的是长度为k的窗口, k = len(p)
        while i < n:
            c = s[i]
            # 当前需要匹配的字母c的次数减1
            if c in dic: dic[c] -= 1
            # 当前这个字母的次数满足要求
            if c in dic and dic[c] == 0:
                staisfy += 1
            while i - j + 1 > len(p):
                # 删除最左边的字符如果删除的字符刚好是满足种类的数目那么satisfy需要减1
                if s[j] in dic and dic[s[j]] == 0: staisfy -= 1
                if s[j] in dic:
                    dic[s[j]] += 1
                j += 1
            #  注意这里是字典的大小
            if staisfy == len(dic): res.append(j)
            i += 1
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值