力扣hot100:找到字符串中所有字母异位词(滑动窗口 + 字符频率数组)(438)
题目描述
解题思路
使用滑动窗口配合字符频率数组高效解决问题:
- 字符频率数组:统计
p
中每个字符的出现频次。 - 滑动窗口:在
s
上维护一个长度等于p
的窗口,动态统计窗口内字符频次。 - 频次匹配:当窗口的字符频次与
p
的频次完全一致时,记录窗口起始索引。
优化点:
- 跳过字符串转列表操作,直接操作字符串降低开销。
- 避免无效比较:仅当窗口长度达到
p
的长度时才进行频次比对。
代码实现
public List<Integer> findAnagrams(String s, String p) {List<Character> s_list = s.chars().mapToObj(c->(char)c).collect(Collectors.toList());List<Character> p_list = p.chars().mapToObj(c->(char)c).collect(Collectors.toList());List<Integer> result=new ArrayList<>();int length=s_list.size();// 改进的滑动窗口实现int pLen = p_list.size();if (s_list.size() < pLen) return result;// 创建字符频率数组int[] pCount = new int[26];int[] windowCount = new int[26];// 统计p中字符频率for (char c : p_list) {pCount[c - 'a']++;}// 滑动窗口for (int i = 0; i < s_list.size(); i++) {// 添加右边字符到窗口windowCount[s_list.get(i) - 'a']++;// 如果窗口大小超过p的长度,移除左边字符if (i >= pLen) {windowCount[s_list.get(i - pLen) - 'a']--;}// 比较窗口和p的字符频率if (Arrays.equals(pCount, windowCount)) {result.add(i - pLen + 1);}}return result;}
算法解析
初始化频率数组:
pCount
记录p
的字符频次,window
动态记录窗口内字符频次。
滑动窗口操作:
- 右扩:遍历
s
,将当前字符加入窗口(window
对应位置+1
)。 - 左缩:当窗口长度超过
p
时,移除窗口最左侧字符(window
对应位置-1
)。
- 右扩:遍历
匹配判断
复杂度分析
- 时间复杂度:O(n),其中
n
是s
的长度。每个字符被操作两次(加入和移除窗口),频次比较操作可忽略(固定26次)。 - 空间复杂度:O(1),仅使用固定大小的频率数组(长度26)。
关键点总结
- 滑动窗口:动态维护窗口内字符频次,避免重复计算。
- 边界处理:及时移除窗口左侧字符,确保长度始终 ≤
p
。 - 性能优化:直接操作字符串代替转列表,减少不必要比较。
通过滑动窗口 + 字符频次数组,高效解决字母异位词子串搜索问题,适合处理字符串匹配类题目!