目录

算法014找到字符串中所有字母异位词

目录

算法014——找到字符串中所有字母异位词

(点击跳转)

https://i-blog.csdnimg.cn/direct/6a598c1dcd8a41b680e50c9ba2696837.png

如果 P = “abc”,那么下图中的都是它的异位词。

https://i-blog.csdnimg.cn/direct/4da1c53b358647dfa8d3679af6f8a5f1.jpeg

在 S 中找到 P 的异位词后,要返回起始位置的下标。

https://i-blog.csdnimg.cn/direct/3af9ee842a44474296480652b75e01ce.jpeg

做这道题之前,我们要知道如何判断两个字符串是否是异位词,其实我们可以统计每个字符出现的次数,如果两个字符串中每个字符出现的次数相等,那么他们就是异位词。利用哈希表即可

https://i-blog.csdnimg.cn/direct/143186ebe1704d4097450455007ff954.jpeg

我们定义一个变量 m 表示 p 字符串的长度,我们将 p 字符串中字母出现的次数存放在 hash1 中,在 s 这个字符串中,找到长度为 m 的子串 ,将次数存放到 hash2 中,然后比较两个哈希表是否相等就可以。

https://i-blog.csdnimg.cn/direct/c877005976694545aa1b3d698b6f31a5.jpeg

其实我们没有必要每次都将 m 个字母的次数都存放在哈希表中 ,如下图所示,红色为第一次枚举放入到哈希表中,粉色为第二次枚举放入到哈希表中,被荧光笔涂到的区域其实已经在哈希表中了,没必要再次存放, 只需要将 c 从哈希表中删除,在将 e 添加到哈希表中即可

https://i-blog.csdnimg.cn/direct/0a839487e1634e79ac77b5a795589b46.jpeg

所以,我们可以使用滑动窗口的方法来解决此问题。

https://i-blog.csdnimg.cn/direct/8f62b645cf434ae7b675b9b56739dc67.jpeg

  1. left = 0,right = 0

  2. 进窗口 :hash2[in]++

  3. 判断 :right - left + 1 > m

    出窗口 :hash2[out]–

    更新结果 :check(hash1,hash2)(比较两个哈希表是否相等)

在更新结果当中,我们需要遍历两个哈希表来进行check,比较麻烦,所以我们对更新结果的判断条件进行优化。

我们定义一个变量 count 来统计 窗口有效字符 的个数

如下图所示,当 c 进入窗口之后,与 hash1 中 c 字符出现的次数比较,有两种清情况。

  1. 小于等于 hash1 中的……,说明 c 为有效字符,让 count + 1

    https://i-blog.csdnimg.cn/direct/ef89f3dac5a54ec1b4da490eacc39fee.jpeg

    之后 right 继续右移,然后放入到 hash2 中

  2. 大于 hash1 中的……,count 不更新

    https://i-blog.csdnimg.cn/direct/724c7fde5e12403399aefadbb990ef08.jpeg

    接下来,right 右移

    https://i-blog.csdnimg.cn/direct/c2d62a7483f94a79bab39b3d26ba83a6.jpeg

    right 继续右移

    https://i-blog.csdnimg.cn/direct/703b9ff2cbbc4e23a5f330d45e6e1c37.jpeg

此时,窗口大于 m ,让 left 右移,再将第一个 c 从 hash2 中删除之前,我们要先判断此时这个字符出现的次数是否大于 hash1 中的次数,这种情况,显然是大于,那么删掉的就是无效字符,count 不需要变化,此时 c 的个数变成了 1。

https://i-blog.csdnimg.cn/direct/cf093da4313a4063bea1314e6dacc606.jpeg

然后我们再判断 count是否等于m,此时count == m,那么窗口中的字符就是 p 的异位词,输出起始位置下标

https://i-blog.csdnimg.cn/direct/09d4be973b2c4bf38792f495b26273f8.jpeg

接下来的遍历就省略了

  1. 进窗口 :hash2[in] <= hash1[in] ——> count++
  2. 出窗口 :hash2[out] <= hash1[out] ——> count–
  3. 更新结果 :count==m

代码如下:

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> ret = new ArrayList<Integer>();
        char[] s1 = s.toCharArray();
        char[] p1 = p.toCharArray();
        int[] hash1 = new int[26];
        for(char ch : p1){
            hash1[ch - 'a']++;
        }
        int[] hash2 = new int[26];
        int m = p.length();
        for(int left = 0,right = 0,count = 0;right < s1.length;right++){
            char in = s1[right];
            if(++hash2[in - 'a'] <= hash1[in - 'a']){
                count++;
            }
            if(right - left + 1 > m){
                char out = s1[left++];
                if(hash2[out - 'a']-- <= hash1[out - 'a']){
                    count--;
                }
            }
            if(count == m){
                ret.add(left);
            }
        }
        return ret;
    }
}

今日任务完成,嘻嘻

https://i-blog.csdnimg.cn/direct/f0cd29817cff4e3481e551c40578ec2d.jpeg