题目
给定一个字符串 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" 的字母异位词。
思路
-
拿到题目的第一时间先确定题目意思,显然是需要在
p.length()这个滑动窗口上进行比较 -
提炼核心:比较subString的结果和p中的字符及字符数量是否一致
-
开始想得做法是: 方案一:
- 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(),继续遍历
- p转char[],再使用Arrays.sort(char[])进行排序,使用
-
提交完之后发现时间耗费有点大,主要是因为
Arrays.sort(char[])内部使用的是快速排序,时间复杂度为O(nLogn),发现为什么不直接遍历字符串,获取一个数组来统计char的频率,降低时间复杂度为O(n) -
判断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 春招闯关活动」, 点击查看 活动详情