算法—leetcode—438—找到字符串中所有字母异位词

517 阅读2分钟

题目

  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" 的字母异位词。

思路

框架

/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
    unordered_map<char, int> need, window;
    // 初始化字串所有元素的个数
    for (char c : t) need[c]++;

	// 初始化左右指针
    int left = 0, right = 0;
    // 有效性的个数
    int valid = 0;
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        /*** debug 输出的位置 ***/
        printf("window: [%d, %d)\n", left, right);
        /********************/

        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

代码

package leetcode

// findAnagrams
// 438. 找到字符串中所有字母异位词
func findAnagrams(s, p string) []int {
    // 初始化计数器,分别记录【窗口】中字符的出现次数和T中字符串出现次数
	window := map[byte]int{}
	need := map[byte]int{}
	for i := 0; i < len(p); i++ {
		cur := p[i]
		need[cur]++
	}
	// 初始化窗口的两端,区间[left, right)
	left, right := 0, 0

	// 表示窗口中满足need条件的字符个数
	// 如果valid和len(need)的大小相同,则说明窗口已满足条件,已经完全覆盖了字符串t
	valid := 0
    
    // 保存结果
    data := []int{}
    
    // 结束条件:存在满足条件的节点即可
	for right < len(s) {
        // 即将移入窗口的值
		cur := s[right]
        right++
        
		// 进行窗口数据更新
        // 首先校验是否在T串
		if _, ok := need[cur]; ok {
			window[cur]++

			// 表示窗口中满足need条件的字符个数
			if window[cur] == need[cur] {
				valid++
			}
		}

		// 判断窗口是否需要收缩:窗口大小大于len(need)时,应为排列,显然长度应该是一样的。
		for (right - left) >= len(p) {
            // 结束条件:在这里判断是否找到了合法的子串,如果合法则将左指针存入结果中
            if valid == len(need){
                data = append(data, left)
            }
            
			// 将移出窗口的字符
			delS := s[left]
			left++
			if _, ok := need[delS]; ok {
                // 既要移除窗口的值,也要移除验证的值
				if window[delS] == need[delS] {
					valid--
				}
				window[delS]--
			}
		}
	}
    return data
}

同类

算法—leetcode—567—字符串的排列
算法—leetcode—76—最小覆盖子串

参考

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/fi…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

labuladong的算法小抄