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

题目描述

思路 and Swift 题解
使用 Swift 重新解这道题目的时候卡了我一段时间,发现我之前使用 C++ 和 Go 解这道题目的时候的思路过于复杂了,因此好好整理分析一下这道题目。
这道题目要找出的是字符串s
当中的子串的开始下标,这些子串满足其中出现字母的个数与p
字符串当中字母出现的次数相同。根据这个条件,我们自然想到应该使用字典来对字符串出现的次数进行存储。与 Golang 不同的是,Swift 的两个字典可以直接进行相等比较,当两个字典当中 Key / Value 完全相同时,这两个字典就是相同的(Golang 当中的 map 只能和 map 的零值 nil 进行比较)。
因此,我们需要先维护一个关于字符串p
的字典mp
,它的类型是[Character: Int]
,因此,我们需要先将String
类型的字符串p
转为[Character]
。之后,将p
字符串当中的字符出现次数维护到到mp
当中。
现在我们需要做的就是维护关于s
子串当中字符出现频率的字典ms
。由于子串必须是连续的,并且长度不会比p
更长,因此我们只需要维护字符串p
长度m
的滑动窗口即可。每次我们需要判断左侧的字符是否已经落入了窗口之外,如果是的话就需要将这个字符出现的频率-1
。如果这个字符出现的频率为0
,就需要将ms
当中它的出现频率设为nil
(原因是ms
和mp
进行比较时,Key / Value 需要完全相同,Value 为0
和 Value 为nil
是不同的)。
如果滑动窗口的大小大于等于m
,就可以开始判断是否存在答案了。如果ms == mp
,就将滑动窗口的左侧索引加入到答案当中。
完整的 Swift 题解是:
swift
class Solution {
func findAnagrams(_ s: String, _ p: String) -> [Int] {
var chars = Array(s), charp = Array(p)
var ms = [Character: Int](), mp = [Character: Int]()
for i in 0..<charp.count {
mp[charp[i], default: 0] += 1
}
var ans = [Int]()
var n = chars.count, m = charp.count
for i in 0..<n {
ms[chars[i], default: 0] += 1
if i >= m {
var leftChar = chars[i - m]
ms[leftChar, default: 0] -= 1
if ms[leftChar] == 0 {
ms[leftChar] = nil
}
}
if i >= m - 1 && ms == mp {
ans.append(i - m + 1)
}
}
return ans
}
}