「这是我参与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
}
结语
业精于勤,荒于嬉;行成于思,毁于随。