🙉饭不食,水不饮,题必须刷🙉
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
LeetCode 太难?先看简单题! 🧡《C语言入门100例》🧡
数据结构难?不存在的! 🌳《画解数据结构》🌳
闭关刷 LeetCode,剑指大厂Offer! 🌌《LeetCode 刷题指引》🌌
LeetCode 太简单?算法学起来! 💜《夜深人静写算法》💜
一、题目
1、题目描述
给定两个长度小于 1 0 5 10^5 105 的字符串 s 1 s_1 s1 和 s 2 s_2 s2,写一个函数来判断 s 2 s_2 s2 是否包含 s 1 s_1 s1 的排列。即 第一个字符串的排列之一 是 第二个字符串 的 子串 。
样例输入1: s 1 s_1 s1 = “ a b ab ab” s 2 s_2 s2 = “ e i d b a o o o eidbaooo eidbaooo”
样例输出1: t r u e true true
样例输入2: s 1 s_1 s1 = “ a b ab ab” s 2 s_2 s2 = “ e i d b z a o o o eidbzaooo eidbzaooo”
样例输出2: f a l s e false false
2、基础框架
- c++ 版本给出的基础框架代码如下:
class Solution {
public:
bool checkInclusion(string s1, string s2) {
}
};
- 其中
string
是 C++ 的 STL 中的模板类,可以用来做字符串的各种操作;
3、原题链接
二、解题报告
1、思路分析
- 用 双指针 配合 哈希表,首先用一个
hash
表来记录 s 1 s_1 s1 中每个字符的出现次数。然后对 s 2 s_2 s2 字符串进行双指针算法,对于选取的子串,如果能和 s 1 s_1 s1 的每个字符的数量完全匹配,那就能满足题目的条件。 - 双指针算法又叫尺取法,详细的算法可以参考:夜深人静写算法(二十八)- 尺取法。
2、时间复杂度
- 两个指针都只会递增各一次,所以时间复杂度为 O ( n ) O(n) O(n)。
3、代码详解
class Solution {
int hash[257];
public:
bool checkInclusion(string s1, string s2) {
memset(hash, 0, sizeof(hash));
for(int i = 0; i < s1.length(); ++i) {
++hash[ s1[i] ]; // (1)
}
int len = s2.length(); // (2)
int i = 0, j = -1;
while(j++ < len - 1) { // (3)
--hash[ s2[j] ]; // (4)
while(hash[ s2[j] ] < 0) { // (5)
++hash[ s2[i] ]; // (6)
++i;
}
if(j - i + 1 == s1.length()) { // (7)
return true;
}
}
return false;
}
};
- ( 1 ) (1) (1) 代表一开始是空串;
-
(
2
)
(2)
(2) 之所以要这么做,是因为
s.length()
是无符号整型,当j == -1
的情况为无符号整型的最大值,永远都无法进入下面的while(j++ < len - 1)
这个循环; - ( 3 ) (3) (3) 尝试向右移动 右指针;
- ( 4 ) (4) (4) 对新加入的字符,进行计数;
- ( 5 ) (5) (5) 合法性判定:选取的 s 2 s_2 s2 子串中的各个 s 1 s_1 s1 中字符个数必须不能超过 s 1 s_1 s1 的个数;
- ( 6 ) (6) (6) 尝试向右移动 左指针;
-
(
7
)
(7)
(7) 如果选取的
s
2
s_2
s2 合法子串长度正好和
s
1
s_1
s1 相等,则表明找到了满足题目条件的子串,返回
true
;
三、本题小知识
尺取法问题大同小异,是可以整理出模板的。