夯实算法-找到字符串中所有字母异位词

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的20天,点击查看活动详情

题目:LeetCode

给定两个字符串 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 . l e n g t h , p . l e n g t h < = 3 1 0 4 1 <= s.length, p.length <= 3 * 10^4
  • s 和 p 仅包含小写字母

解题思路

如何判断变位词,可以用一个map,变位词,顺序变化,但是字符出现的数量是一样的,比如"abc",与"bca",如果都 放进map中,则数量是一样的,此方法 可以用来判断是否是一个变位词。

map本身,因为都 是小写字母,且数量是30000以内,所以用一个长度为26的short数组就可以了,下标是字符-'a',元素的值就是其出现的数量。

因为变位词的字符集的数量是一样的,所以先把p字串的所有字符都 加入map,然后不断的从s的子串中的字符数量减1,如果map全是0,则遇到 一个变位词子串。

子串由[left, right]指定,其长度是固定的,每次右指针向前步进,向子串中添加一个新的字符,要从map中把其减去1,同时要保持子串数量为p.length(),所以需要把最左的边的字符从子串中剔除去,也就是说要向右移动一下左指针。前面加入到子串中的字符是数量减1,那么从子串中剔除,就要把其数量加回来。之后判断map是否为0即可。

代码实现

public List < Integer > findAnagrams(String s, String p) {
    List < Integer > result = new ArrayList();
    if (s.length() < p.length()) {
        return result;
    }

    short[] map = new short[26];
    for (int i = 0; i < p.length(); i++) {
        map[p.charAt(i) - 'a'] ++;
        map[s.charAt(i) - 'a'] --;
    }
    if (allZero(map)) {
        result.add(0);
    }
    for (int i = p.length(); i < s.length(); i++) {
        map[s.charAt(i) - 'a'] --;
        map[s.charAt(i - p.length()) - 'a'] ++;
        if (allZero(map)) {
            result.add(i - p.length() + 1);
        }
    }

    return result;
}

private static boolean allZero(short[] counts) {
    for (short c: counts) {
        if (c != 0) {
            return false;
        }
    }

    return true;
}
复制代码

运行结果

Snipaste_2022-12-17_20-57-21.png

复杂度分析

  • 空间复杂度: O ( n ) O(n)
  • 时间复杂度: O ( n 2 ) O(n^2)

掘金(JUEJIN)  一起分享知识, Keep Learning!

猜你喜欢

转载自juejin.im/post/7178102549059698747