002-找到字符串中所有字母异位词-2020.03.08 |刷题打卡

147 阅读3分钟

题目

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。

字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

字母异位词指字母相同,但排列不同的字符串。 不考虑答案输出的顺序。 示例 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. 拿到题目的第一时间先确定题目意思,显然是需要在p.length()这个滑动窗口上进行比较

  2. 提炼核心:比较subString的结果和p中的字符及字符数量是否一致

  3. 开始想得做法是: 方案一:

    • p转char[],再使用Arrays.sort(char[])进行排序,使用String.copyValueOf(new char[])获得新的字符串s1
    • 遍历数组s,获取index=i
    • substring转char[],再使用Arrays.sort(char[])进行排序,得到一个char[],再转换为字符串s2
    • 判断s2.equals(s1),然后继续
    • 如果相等,判断s.charAt(i+p.length())和当前字符是否一致s.charAt(i),一致i++,并存进最终数组
    • 不一致且p不包含该字符,i=i+p.length(),继续遍历
  4. 提交完之后发现时间耗费有点大,主要是因为Arrays.sort(char[])内部使用的是快速排序,时间复杂度为O(nLogn),发现为什么不直接遍历字符串,获取一个数组来统计char的频率,降低时间复杂度为O(n)

  5. 判断p和subString的逻辑更改为 方案二:

    • 外层遍历字符串p,获取词频==>都是26个字母的char==>核心逻辑

              char[] chars2 = p.toCharArray();
              char[] free = new char[26];
              for (char c : chars2) {
                  free[c - 'a']++;
              }
      
    • 截取字符串substring,同样获取一个新的char数组,判断两个数组是否相等

              char[] chars = s.substring(i, i + pL).toCharArray();
              char[] free2 = new char[26];
              for (char c : chars) {
                  free2[c - 'a']++;
              }
              boolean flag = true;
              for (char c : chars2) {
                  if (free[c - 'a'] != free2[c - 'a']) {
                      flag = false;
                      break;
                  }
              }
      
    • 时间复杂度降低,执行耗时显著降低

code

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> list = new ArrayList<>();
        int pL = p.length();
        char[] chars2 = p.toCharArray();
        char[] free = new char[26];
        for (char c : chars2) {
            free[c - 'a']++;
        }
        for (int i = 0; i <= s.length() - pL; i++) {
            if (!p.contains(s.charAt(i) + "")) {
                continue;
            }
            char[] chars = s.substring(i, i + pL).toCharArray();
            char[] free2 = new char[26];
            for (char c : chars) {
                free2[c - 'a']++;
            }
            boolean flag = true;
            for (char c : chars2) {
                if (free[c - 'a'] != free2[c - 'a']) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                list.add(i);
                while (i + pL < s.length() && s.charAt(i) == s.charAt(i + pL)) {
                    list.add(i + 1);
                    i++;
                }
                if (i + pL < s.length()) {
                    char at = s.charAt(i);
                    char at1 = s.charAt(i + pL);
                    if (at != at1 && !p.contains(at1 + "")) {
                        i = i + pL;
                    }
                }
            }
        }
        return list;
    }
}

截图

执行截图

  • 本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情