1、题目描述
2、题目解析
题目中出现了一个名词,【异位词】异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
此题可以用经典的【滑动窗口解法】,从网上找到了一个大神(labuladong)的打油诗:
可以参考滑动窗口共用模板进行代码实现完善,公共模板参考之前梳理文章,链接如下:
【滑动窗口】子串问题全靠它。左右指针滑窗口。此类算法的模板代码显示如下:
int left = 0, right = 0;
while (right < s.size()) {
// 增大窗口
window.add(s[right]);
right++;
while (window needs shrink) {
// 缩小窗口
window.remove(s[left]);
left++;
}
}
真的是怒赞暴力推荐大神lubuladong 的这套全解析【简直是神操作】:力扣https://leetcode.cn/problems/find-all-anagrams-in-a-string/solution/hua-dong-chuang-kou-tong-yong-si-xiang-jie-jue-zi-/
从而相关的一系列题目都迎刃而解了
自梳理的代码实现【JAVA版】
class Solution {
public List<Integer> findAnagrams(String s, String p) {
Map<Character,Integer> need = new HashMap<Character,Integer>();
Map<Character,Integer> window = new HashMap<Character,Integer>();
for(char c : p.toCharArray()){
if(need.containsKey(c)){
need.put(c,need.get(c)+1);
}else{
need.put(c,1);
}
}
int left = 0;
int right = 0;
int valid = 0;
List<Integer> res = new ArrayList<Integer>();
while(right < s.length()){
char c = s.charAt(right);
//滑动窗口右移
right++;
if(window.containsKey(c)){
window.put(c, window.get(c)+1);
}else{
window.put(c, 1);
}
//如果两个map中该元素个数一致,则有效数据增加
if(window.get(c).equals(need.get(c)))
valid++;
//判断左侧窗口是否要收缩,这样限制了(right-left)的区间长度
while((right-left) >= p.length()){
if(valid == need.size()){
res.add(left);
}
//滑动窗口进行收缩
char d = s.charAt(left);
left++;
if(need.containsKey(d)){
if(window.get(d).equals(need.get(d)))
valid--;
window.put(d,window.get(d)-1);
}
}
}
return res;
}
}
复杂度分析
时间复杂度:最坏情况下左右指针对 s 的每个元素各遍历一遍,哈希表中对 s 中的每个元素各插入、删除一次,对 p 中的元素各插入一次。每次检查是否可行会遍历整个 p 的哈希表,哈希表的大小与字符集的大小有关,则渐进时间复杂度为 O(∣s∣+∣p∣)。
空间复杂度:这里用了两张哈希表作为辅助空间,每张哈希表最多不会存放超过字符集大小的键值对,我们设字符集大小都不会超过字符串本身 ,则渐进空间复杂度为 O(∣s∣+∣p∣)。
解题特点:
比较字符出现次数时,window.get(d).equals(need.get(d)) ,之前写成 window.get(d) == (need.get(d)) 对于长字符就会出错,Integer 在大于127 的时候是【对象】,因此不能使用数字模式进行比较了!