字符串的排列
题目描述
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).
示例2:
输入: s1= “ab” s2 = “eidboaoo”
输出: False
注意:
输入的字符串只包含小写字母
两个字符串的长度都在 [1, 10,000] 之间
滑动窗口+哈希+双指针
class Solution {
// 判断 s2 中是否存在 s1 的排列
/*
使用滑动窗口算法,相当给你一个 S 和一个 T,请问你 S 中是否存在一个子串,包含 T 中所有字符且不包含其他字符?是:valid==need.size()
*/
public boolean checkInclusion(String s1, String s2) {
// 排除异常的边界情况,也限定了模式串的长度
if(s1.length() > s2.length()) {
return false;
}
// 模式串的字典:可以看做一种频率分布
Map<Character, Integer> need = new HashMap<>();
for(int i = 0; i < s1.length(); i++) {
need.put(s1.charAt(i), need.getOrDefault(s1.charAt(i), 0 ) + 1);
}
// 动态更新的匹配窗口字典
Map<Character, Integer> window = new HashMap<>();
int left = 0, right = 0;
int valid = 0;
while(right < s2.length()) {
char c = s2.charAt(right);
right++;
// 进行窗口内数据的一系列更新
if(need.containsKey(c)) {
window.put(c, window.getOrDefault(c, 0) + 1);
if(need.get(c).equals(window.get(c))) {
valid++;
}
}
//判断左侧窗口是否需要收缩
while(right - left >= s1.length()) {
// 在这里判断是否找到了合法的子串
if(valid == need.size()) {
return true;
}
char d = s2.charAt(left);
left++;
// 进行窗口内数据的一系列更新
if(need.containsKey(d)) {
if(need.get(d).equals(window.get(d))) {
valid--;
}
window.put(d, window.get(d) - 1);
}
}
}
// 未找到符合条件的子串
return false;
}
}
参考:滑动窗口