)
1. 题目回顾给定两个字符串s和p找到s中所有p的异位词字母相同、排列不同的子串返回这些子串的起始索引。例如输入s cbaebabacdp abc输出[0, 6]因为s[0..2] cba和s[6..8] bac都是abc的异位词。2. 核心思路本题是典型的固定长度滑动窗口问题。窗口大小固定为p的长度在s上从左向右滑动每次判断窗口内的子串是否为p的异位词。判断异位词的关键在于字符频率完全一致窗口内每个字符的出现次数必须与p中对应字符的出现次数相同。为了高效判断我们使用两个哈希表pMap统计p中每个字符的频率目标频率。windowMap统计当前窗口中每个字符的频率实时频率。同时用一个计数器matched记录已经达到目标频率的字符种类数。当matched pMap.size()时说明窗口中所有字符的频率都与p完全一致即找到了一个异位词。3. 代码实现classSolution{publicListIntegerfindAnagrams(Strings,Stringp){ListIntegerresultnewArrayList();intsLens.length(),pLenp.length();if(sLenpLen)returnresult;MapCharacter,IntegerpMapnewHashMap();MapCharacter,IntegerwindowMapnewHashMap();// 统计 p 中字符频率for(charc:p.toCharArray()){pMap.put(c,pMap.getOrDefault(c,0)1);}intleft0,right0;intmatched0;// 记录有多少个字符匹配了频率while(rightsLen){charrChars.charAt(right);// 加入右边界字符if(pMap.containsKey(rChar)){windowMap.put(rChar,windowMap.getOrDefault(rChar,0)1);// 只有匹配频率的时候才会 1 字符if(windowMap.get(rChar).intValue()pMap.get(rChar).intValue()){matched;}}right;// 当窗口大小等于 p 的长度时while(right-leftpLen){// 如果所有字符都匹配记录起始索引if(matchedpMap.size()){result.add(left);}// 移除左边界字符charlChars.charAt(left);if(pMap.containsKey(lChar)){if(windowMap.get(lChar).intValue()pMap.get(lChar).intValue()){matched--;}windowMap.put(lChar,windowMap.get(lChar)-1);}left;}}returnresult;}}4. 关键细节解析4.1 为什么用matched而不是直接比较两个 Map如果每次窗口滑动都重新比较两个哈希表时间复杂度是O(26)或O(pMap.size())整体会退化为O(n * 26)。而用matched计数器每次窗口滑动只需要常数次更新整体时间复杂度为O(n)效率更高。4.2 右边界扩展时的matched更新if(windowMap.get(rChar).intValue()pMap.get(rChar).intValue()){matched;}只有当rChar在窗口中的频率恰好等于目标频率时matched才加一。注意这里用的是判断意味着如果频率从目标值 - 1增加到目标值matched如果频率继续增加超过目标值matched不再变化因为已经不等于目标值了。4.3 左边界收缩时的matched更新if(windowMap.get(lChar).intValue()pMap.get(lChar).intValue()){matched--;}移除左边界字符前先判断它当前的频率是否恰好等于目标频率。如果是说明移除后频率会低于目标值matched需要减一。4.4 为什么用intValue()windowMap.get(rChar)返回的是Integer对象。如果直接用比较两个Integer在值超过127时会因为对象引用不同而返回falseInteger缓存机制只覆盖-128 ~ 127。虽然本题字符频率不会超过s的长度理论上可能超过127所以用intValue()转成基本类型再比较是更稳妥的写法。5. 复杂度分析时间复杂度O(n)其中n是字符串s的长度。每个字符最多被加入窗口一次、移出窗口一次每次操作都是常数时间。空间复杂度O(1)。两个哈希表最多存储 26 个字符小写字母与输入规模无关。6. 总结本题的核心技巧是用matched计数器代替每次滑动都重新比较哈希表将判断异位词的时间从O(26)降为O(1)从而把整体复杂度控制在O(n)。理解matched在窗口扩展和收缩时的更新时机是掌握这类「固定长度滑动窗口 频率匹配」题目的关键。