WELCOME TO Pluto134340小行星

清风湿润,茶烟轻扬。

9.找到字符串中所有字母异位词

438. 找到字符串中所有字母异位词
 给定两个字符串 s 和 p,找到 s 中所有 p 的  的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

 示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

 示例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

 提示:

  • 1 <= s.length, p.length <= 3 * 104
  • s 和 p 仅包含小写字母
  思路1——定长滑动窗口

列表比较,实现可以计数也可以判断有哪些 cnS  cnP

使用定长滑动窗口,右端从0开始遍历s ,可以实现遍加入元素边比较。因此需要做到当左端 left<0 时,不处理比较和左端“出栈”。

        // 按照惯性思维应该是先左边出 再右边近。这样得保证right从p.length()处开始【p长度为三,right就从3开始,left从0开始】,需要多一步先赋值前p.length() 的s'【逻辑清晰 代码复杂一点,多一步赋值】
        // 按照下面代码可以实现,left<0时跳过比较和左端出,实现小于0时只进窗口。
 
注意:p.toCharArray() 字符串转数组;
s.charAt( i ) s 中下标为 i 的字符;
int[] index = new int[]; 为什么不能采用数组方式定义??——> 这样定义会报错,因为是固定长度又没有传参数告知多长。明显题目中长度是不固定的
数组和 List 的核心区别:数组是固定长度、通过下标操作;List(ArrayList)是动态长度、通过 add()/get() 等方法操作
 1 class Solution {
 2     public List<Integer> findAnagrams(String s, String p) {
 3         int[] cnS = new int[26];
 4         int[] cnP = new int[26];
 5         // int[] index = new int[];  为什么不能采用这种方式定义??
 6         List<Integer> ans = new ArrayList<>();
 7         int left = 0;
 8         // cnP 统计p中字母
 9         for(char ss : p.toCharArray()){
10             cnP[ss-'a']++;
11         }
12 
13         // cnS 统计s 的子串s'的字母
14         // 按照惯性思维应该是先左边出 再右边近。这样得保证right从p.length()处开始【p长度为三,right就从3开始,left从0开始】,需要多一步先赋值前p.length() 的s'【逻辑清晰 代码复杂一点,多一步赋值】
15         // 按照下面代码可以实现,left<0时跳过比较和左端出,实现小于0时只进窗口。
16         //定长窗口可以考虑先进后出。【针对本题】
17         for(int right = 0; right < s.length(); right++){
18             cnS[s.charAt(right) - 'a']++;   // 右端进入窗口
19             left = right - p.length() + 1;
20             if(left<0) continue;
21 
22             if(Arrays.equals(cnS ,cnP)){
23                 ans.add(left);
24             }
25             cnS[s.charAt(left) - 'a']--;    // 左端出窗口
26         }
27         return ans;
28     }
29 }
View Code

 

思路2——不定长滑动窗口【作者:灵茶山艾府 来源:力扣(LeetCode)】

枚举子串 s ′  的右端点,如果发现 s ′  其中一种字母的出现次数大于 p 的这种字母的出现次数,则右移 s ′  的左端点(缩小窗口)。如果发现 s ′  的长度等于 p 的长度,则说明 s ′  的每种字母的出现次数,等于 p 的每种字母的出现次数,即 s ′  是 p 的异位词。

只判断窗口右端字母:
cnt[ ] 用于记录字符元素出现哪些,出现几次。先遍历 p ,cnt[i]+1;再遍历s cnt[i] - 1。当cnt[i]<0时,说明p中没有这个字符,或者p中这个字符的数量没有s’ 多。

这时候就需要缩小窗口,直到cnt[i]>=0【cnt 回到加入字符 i 前的状态,同时left 窗口左端 移动到字符i 后一个位置 】

注意: while 部分有点绕,left  初始为0,当出现不匹配字符时候再回出来复原 cnt 调整窗口左端,将窗口左端移动到不匹配字符的下一个位置。

 1 class Solution {
 2     public List<Integer> findAnagrams(String s, String p) {
 3         int[] cnt = new int[26];
 4         List<Integer> ans = new ArrayList<>();
 5         int left = 0;
 6         // cnt 统计p中字母。拿着cnt当模板比较s'
 7         for(char ss : p.toCharArray()){
 8             cnt[ss-'a']++;
 9         }
10 
11         for(int right = 0; right < s.length(); right++){
12             int idx = s.charAt(right) - 'a';
13             cnt[idx]--;   // 右端进入窗口
14 
15             while(cnt[idx] < 0){
16                 cnt[s.charAt(left)-'a']++; // 复原窗口,移动窗口左端
17                 left++;
18             }
19 
20             if(right-left+1==p.length()) ans.add(left);
21 
22         }
23         return ans;
24     }
25 }
View Code

 

posted @ 2026-01-10 20:33  Pluto134340  阅读(2)  评论(0)    收藏  举报