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

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

image

方法一:简单滑动窗口

满足异位词条件:

(1)s中子串s' 与 目标字符串p的长度相等

(2)s'与p中字母相同(对排列方式没有要求)

算法思路:在字符串s中构造一个长度与字符串p的长度相同的滑动窗口截取子串s‘,并在窗口中维护每种字母的数量。当s'的每种字母数量与目标串p的每种字母数量相同,则说明当前窗口为字符串p的异位词。

技巧:可以使用数组记录字符串每种字母的个数,最后比较s'与p的记录数组即可。

public List<Integer> findAnagrams(String s, String p) {
    int[] pCount = new int[26];
    List<Integer> result = new ArrayList<>();
    int sLength = s.length();
    int pLength = p.length();
    if (sLength < pLength) {
        return result;
    }

    for (int i = 0; i < pLength; i++) {
        ++pCount[p.charAt(i) - 'a'];
    }
    int lo = 0;
    int hi = pLength;
    // [lo,hi)
    while (hi <= sLength) {
        int[] sCount = new int[26];
        int x = lo;
        for (int i = lo; i < hi; i++) {
            ++sCount[s.charAt(i) - 'a'];
        }
        if (Arrays.equals(sCount, pCount)) {
            result.add(x);
        }
        // 滑动窗口
        hi++;
        lo++;
    }
    return result;
}

方法二 :改进滑动窗口

​ 方法一中每次都需要对子串s' 进行重新统计,然后再一一比较。可以每次仅仅考虑lo收缩减少的那个字母以及hi扩张增加的字母。使用diff表示当前存在的数量不同的字母种数

 public List<Integer> findAnagrams(String s, String p) {
        int[] count = new int[26];
        List<Integer> result = new ArrayList<>();
        int sLength = s.length();
        int pLength = p.length();
        if (sLength < pLength) {
            return result;
        }

        for (int i = 0; i < pLength; i++) {
            --count[p.charAt(i) - 'a'];
            ++count[s.charAt(i) - 'a'];
        }
        //指示子串s'与字符串中不同字母的种数
        int diff = 0;
        for (int i = 0; i < 26; i++) {
            if (count[i] != 0) {
                diff++;
            }
        }
        if (diff == 0) {
            result.add(0);
        }
        int lo = 0;

        for (; lo < sLength - pLength; ) {
            // 出lo
            char ch = s.charAt(lo);
            if (count[ch - 'a'] == 0) {
                diff++;
            } else if (count[ch - 'a'] == 1) {
                diff--;
            }
            --count[ch - 'a'];
            char ch1 = s.charAt(lo + pLength);
            if (count[ch1 - 'a'] == -1) {
                diff--;
            } else if (count[ch1 - 'a'] == 0) {
                diff++;
            }
            ++count[ch1 - 'a'];
            lo++;
            if (diff == 0) {
                result.add(lo);
            }
        }
        // [lo,hi)
        return result;
    }

变式

若存在两个字符串t与p,若要求字符串t的长度为|p|+ 4的子串中包含p的全部字母即p为t的异位词,那么判断p是否为t的异位词。(保证|s| > |p|)

对方法而进行修改:

(1)tLenght = min(t.length(), pLength + 4);

(2)第一次对diff取值时,只要count[*] >= 0 即可(表示子串t'中包含了模版p的全部内容)

(3)窗口移除lo时,只需要关注count[*]是否从0 变为负数,这意味增加了一个不满足条件的字母

(4)窗口新增hi时,只需要关注count[*]是否从-1 变为0,这意味着减少了一个不满足条件的字母

posted @ 2022-08-14 13:32  Kyara  阅读(144)  评论(0编辑  收藏  举报