【LeetCode】567. 字符串的排序

238 阅读2分钟

「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战」。

题目

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。

换句话说,s1 的排列之一是 s2 的 子串 。

示例 1

输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").

示例 2

输入:s1= "ab" s2 = "eidboaoo"
输出:false

提示

  • 1 <= s1.length, s2.length <= 104
  • s1 和 s2 仅包含小写字母

题解

思路

s1的任意一种排列,是s2的一个子串。不需要当成全排列问题去做。

等价于,s1的每种字符的出现次数,与 s2 某个子串的每种字符的出现次数相同。

s1 字符的出现次数,生成map,去碰撞s2的子串所对应的map,如果能“全等”,就找到了满足条件的子串。

也可以用长度为 26 的数组来代替map,每个索引对应26个字母。

具体步骤:

  • 创建长度 26 的数组 count1 和 count2,统计 s1 字符的出现次数,到 count1
  • 指针 start,保存所要找的 s2 子串的开头
  • 指针 i 扫 s2,更新当前字符的出现次数到 count2,同时判断 start 上的 s2 字符的出现次数,是否已经大于了它在 s1 的出现次数
    • 如果大于,说明这个字符,s1 并没有那么多,要窗口左移,剔除 start 上的 s2 字符
    • 如果不大于,说明 start 字符在 s2 的出现次数还没达到 s1 的标准,窗口要扩张。纳入新字符
  • 如果遍历过程中 count1 和 count2 全等,说明找到了满足条件的子串,返回 true
  • 如果遍历 s2 结束,始终没有返回真,说明怎么也找不到,返回 false

代码

func checkInclusion(s1 string, s2 string) bool {
    // 两个长度为26的数组
    count1, count2 := [26]int{}, [26]int{}
    // 统计s1的字符的出现次数
    for i := 0; i < len(s1); i++ {
            count1[s1[i]-'a']++
    }
    // 指向s2子串的开头
    start := 0

    // 遍历s2的字符
    for i, c := range s2 {
        // 将s2的字符统计到count2
        count2[c-'a']++
        for start <= i && count1[s2[start]-'a'] < count2[s2[start]-'a'] {
                count2[s2[start]-'a']--
                start++
        }
        // go里面数组是基本类型,可以这么比较
        if count1 == count2 {
                return true
        }
    }
    // 考察了所有s2的字符,都没有找到合适的子串
    return false
}

结语

业精于勤,荒于嬉;行成于思,毁于随。