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

97 阅读3分钟

leetcode.cn/problems/fi…

image.png

解法一:暴力法,定长滑动窗口,遍历数组,逐个子串比较

快速判断异位词的技巧可以参考该题的解法: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
    }

扩展:类似题目