解法一:暴力法,定长滑动窗口,遍历数组,逐个子串比较
快速判断异位词的技巧可以参考该题的解法:juejin.cn/post/746857…
然后我们就可以在原数组上遍历,逐个截取子串进行比较,更新答案
func findAnagrams(s string, p string) []int {
res := make([]int, 0)
ll := len(p)
for i := 0; i < len(s)-ll+1; i++ {
sub := s[i : i+ll]
// 判断子串是否为p的异位词
if isAnagrams(sub, p) {
res = append(res, i)
}
}
return res
}
func isAnagrams(s1, s2 string) bool {
cnt1 := [26]int{}
for _, c := range s1 {
cnt1[c-'a']++
}
cnt2 := [26]int{}
for _, c := range s2 {
cnt2[c-'a']++
}
if cnt1 == cnt2 {
return true
}
return false
}
稍微优化一下,字符串p是固定的,遍历计数一次即可
func findAnagrams(s string, p string) []int {
res := make([]int, 0)
ll := len(p)
cnt_p := [26]int{}
for _, c := range p {
cnt_p[c-'a']++
}
for i := 0; i < len(s)-ll+1; i++ {
sub := s[i : i+ll]
// 判断子串是否为p的异位词
cnt_sub := [26]int{}
for _, c := range sub {
cnt_sub[c-'a']++
}
if cnt_sub == cnt_p{
res = append(res, i)
}
}
return res
}
- 时间复杂度:O(26*m+n),其中 m 是 s 的长度,n 是 p 的长度
- 空间复杂度:O(n),每次循环都要申请额外数组,O(26)
解法二:不定长滑动窗口
func findAnagrams(s string, p string) []int {
need := make(map[string]int) // 记录p字符串中的字母出现个数
window := make(map[string]int) // 记录窗口内的子串每个字母的出现个数
for _, c := range p{
need[string(c)]++
}
left, right := 0, 0
valid := 0 // 记录异位词每个字母相同的次数
res := make([]int, 0)
for right < len(s){
// 判断右指针当前指向元素是否符合异位词
c := string(s[right])
window[c]++
if _, ok := need[c]; ok{
if window[c] == need[c]{
valid++
}
}
// 更新右指针
right++
// 判断左边界是否收缩
// 下面也可以写成框架中的形式 for right - left >= len(p),但实际只会在长度等于p时判断一次
if right - left == len(p){ // 子串长度等于p就需要判断是否异位词
if valid == len(need){ // 每个字母的出现次数都相同,是异位词
res = append(res, left)
}
// 左指针前进,移除左边界元素,更新map
c := string(s[left])
if _, ok := need[c]; ok{
if window[c] == need[c]{
valid--
}
}
window[c]--
left++
}
}
return res
}
优化一下内存占用,window中只需记录异位词所需要的字母出现次数即可
func findAnagrams(s string, p string) []int {
need := make(map[string]int) // 记录p字符串中的字母出现个数
window := make(map[string]int) // 记录窗口内的子串符合p所需字母的出现个数
for _, c := range p{
need[string(c)]++
}
left, right := 0, 0
valid := 0 // 记录异位词每个字母相同的次数
res := make([]int, 0)
for right < len(s){
// 判断右指针当前指向元素是否符合异位词
c := string(s[right])
if _, ok := need[c]; ok{
window[c]++
if window[c] == need[c]{
valid++
}
}
// 更新右指针
right++
// 判断左边界是否收缩
if right - left == len(p){ // 子串长度等于p就需要判断是否异位词
if valid == len(need){ // 每个字母的出现次数都相同,是异位词
res = append(res, left)
}
// 左指针前进,移除左边界元素,更新map
c := string(s[left])
if _, ok := need[c]; ok{
if window[c] == need[c]{
valid--
}
window[c]--
}
left++
}
}
return res
}