LeetCode Hot 100-438找到字符串中所有字母异位词

给定一个字符串 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” 的字母异位词。

首先这个题就是看被比较的字符串的字串会不会有另一个字符串的元素,并且各元素的数量相同。

所以首先想到的解法是排序,每个字串排序,,然后和排序好的p串比较,一样的就是满足条件的,但是是超时的,卡在了 35 / 36 个通过测试用例。也写一下代码

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        sorted_p = sorted(p)
        result = []
        for i in range(len(s) - len(p) + 1):
            if sorted(s[i:i+len(p)]) == sorted_p:
                result.append(i)
        return result

然后由于大数组排序比较占时间,所以变成两个字典比较,以 s: “cbaebabacd” p: “abc”。为例:
字典格式是:{‘a’:1,‘b’:1,‘c’:1}

i i->i+len( p ) p的字典 是否满足
0 {‘a’:1,‘b’:1,‘c’:1} {‘a’:1,‘b’:1,‘c’:1}
1 {‘a’:1,‘b’:1,‘e’:1} {‘a’:1,‘b’:1,‘c’:1}
2 {‘a’:1,‘b’:1,‘e’:1} {‘a’:1,‘b’:1,‘c’:1}
3 {‘a’:1,‘b’:1,‘e’:1} {‘a’:1,‘b’:1,‘c’:1}
4 {‘a’:1,‘b’:2} {‘a’:1,‘b’:1,‘c’:1}
5 {‘a’:2,‘b’:1} {‘a’:1,‘b’:1,‘c’:1}
6 {‘a’:1,‘b’:1,‘c’:1} {‘a’:1,‘b’:1,‘c’:1}
7 {‘a’:1,‘d’:1,‘c’:1} {‘a’:1,‘b’:1,‘c’:1}

代码

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        p_set = set(p)
        p_dic = {}
        for i in range(len(p)):
            if p[i] in p_dic.keys():
                p_dic[p[i]] += 1
            else:
                p_dic[p[i]] = 1
        result = []
        for i in range(len(s) - len(p) + 1):
            if set(s[i:i+len(p)]) == p_set:
                tmp = {}
                for j in s[i:i+len(p)]:
                    if j in tmp.keys():
                        tmp[j] += 1
                    else:
                        tmp[j] = 1
                if tmp == p_dic:
                    result.append(i)
        return result

还是超时,也是在35 / 36 个通过测试用例

最后看了一下高赞的解答:@labuladong

这个解法主要说的是一个滑动窗口,首先我们将left和right指针都指向0
right依次向右移动,并且记录下和p字符串中相关元素出现的个数,如果任意元素数量满足条件,就将标志变量match+1。
当满足条件,我们就向右移动left指针,如果移动过程中去除的都是和p字符串无关的变量,那么标志变量match不会受影响,如果是和p字符串相关的变量,就将字典中该变量数量-1,还要看字典中数量是不是依然满足,满足的话就不会修改match,否则修改match。当right和left的差值是len§的时候,就表示可以添加到最终结果。

最后终于AC了

代码

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        left = 0
        right = 0

        window = {}

        result = []
        need = dict((i, p.count(i)) for i in p)
        match = 0
        while right < len(s):
            if s[right] in need.keys():
                window[s[right]] = window.get(s[right], 0) + 1
                if window[s[right]] == need[s[right]]:
                    match += 1
            right += 1
            while match == len(need):
                if right - left == len(p):
                    result.append(left)
                if s[left] in need.keys():
                    window[s[left]] -= 1
                    if window[s[left]] < need[s[left]]:
                        match -= 1
                left += 1
        return result

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string

你可能感兴趣的:(LeetCode,LeetCode,Hot)