Skip to content

Commit 87a604e

Browse files
committed
438.找到字符串中所有字母异位词,滑动窗口,双指针
1 parent 219c9f1 commit 87a604e

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

leetcode_Java/DoneTitle.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
415. 字符串相加
110110
416. 分割等和子集
111111
437. 路径总和
112+
438. 找到字符串中所有字母异位词
112113
448. 找到所有数组中消失的数字
113114
461. 汉明距离
114115
463. 岛屿的周长

leetcode_Java/DoneType.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
151. 颠倒字符串中的单词(分割反转,双指针,双端队列)
179179
394. 字符串解码(栈)
180180
415. 字符串相加(模拟相加)
181+
438. 找到字符串中所有字母异位词(滑动窗口,双指针)
181182

182183

183184
九、位运算

leetcode_Java/Solution0438.java

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// 438. 找到字符串中所有字母异位词
2+
3+
4+
/*
5+
滑动窗口 + 数组:
6+
1、s的长度小于p时,不能凑成异位词
7+
2、因为字符串中的字符全是小写字母,可以用长度为26的数组记录字母出现的次数
8+
3、设n = len(s), m = len(p)。记录p字符串的字母频次 pCount,和s字符串前m个字母频次 sCount
9+
4、若 pCount 和 sCount 相等,说明两者字母相同,则找到第一个异位词索引 0
10+
5、以p字符串长度m为滑动窗口大小,继续判断s字符串的字符,向右滑动过程,滑动窗口头部增加一个字母,尾部去掉一个字母,增减次数对应记录到sCount
11+
6、每次滑动后都判断 pCount 和 sCount 是否相等,若相等则新增异位词索引
12+
13+
s = "cbaadbac", p = "abca"
14+
15+
sCount = [2,1,1,...], pCount = [2,1,1,...]
16+
c b a a d b a c
17+
↑_____↑
18+
====================
19+
sCount = [2,1,0,1..], pCount = [2,1,1,...]
20+
c b a a d b a c
21+
↑_____↑
22+
*/
23+
class Solution {
24+
public List<Integer> findAnagrams(String s, String p) {
25+
int n = s.length(), m = p.length();
26+
List<Integer> res = new ArrayList<>();
27+
if (n < m) {
28+
return res;
29+
}
30+
int[] sCount = new int[26];
31+
int[] pCount = new int[26];
32+
for (int i = 0; i < m; i++) {
33+
sCount[s.charAt(i) - 'a']++;
34+
pCount[p.charAt(i) - 'a']++;
35+
}
36+
if (Arrays.equals(sCount, pCount)) {
37+
res.add(0);
38+
}
39+
for (int i = m; i < n; i++) {
40+
sCount[s.charAt(i - m) - 'a']--;
41+
sCount[s.charAt(i) - 'a']++;
42+
if (Arrays.equals(sCount, pCount)) {
43+
res.add(i - m + 1);
44+
}
45+
}
46+
return res;
47+
}
48+
}
49+
50+
51+
/*
52+
滑动窗口 + 双指针
53+
1、定义左右指针,从索引0开始
54+
2、右指针向右滑动过程,记录 sCount 增加字母次数,当同一字母 sCount 次数大于 pCount,说明窗口内出现了多余的字母,需要移除,
55+
于是左指针向右滑动,缩小窗口范围,并记录 sCount 减少字母次数,直到该字母次数合法
56+
3、每次 右指针扩大窗口 和 左指针缩小窗口 操作结束后,窗口内的字母都是符合p要求的字母,判断一下窗口大小是否等于p的长度,是则说明窗口内字母凑齐,是异位词,记录起始索引
57+
58+
s = "cbaebabacd", p = "abc"
59+
60+
sCount = [1,1,1,0,...], pCount = [1,1,1,0,...]
61+
c b a d a b c d
62+
↑ ↑
63+
left right
64+
====================
65+
sCount = [1,1,1,1,...], pCount = [1,1,1,0,...]
66+
c b a d a b c d
67+
↑ ↑
68+
left right
69+
====================
70+
sCount = [0,0,0,0,...], pCount = [1,1,1,0,...]
71+
c b a d a b c d
72+
↑ ↑
73+
right left
74+
====================
75+
sCount = [1,1,1,0,...], pCount = [1,1,1,0,...]
76+
c b a d a b c d
77+
↑ ↑
78+
left right
79+
*/
80+
class Solution {
81+
public List<Integer> findAnagrams(String s, String p) {
82+
int n = s.length(), m = p.length();
83+
List<Integer> res = new ArrayList<>();
84+
if (n < m) {
85+
return res;
86+
}
87+
int[] sCount = new int[26];
88+
int[] pCount = new int[26];
89+
for (int i = 0; i < m; i++) {
90+
pCount[p.charAt(i) - 'a']++;
91+
}
92+
int left = 0, right = 0;
93+
while (right < n) {
94+
int index = s.charAt(right) - 'a';
95+
sCount[index]++;
96+
while (sCount[index] > pCount[index]) {
97+
sCount[s.charAt(left) - 'a']--;
98+
left++;
99+
}
100+
if (right - left + 1 == m) {
101+
res.add(left);
102+
}
103+
right++;
104+
}
105+
return res;
106+
}
107+
}

0 commit comments

Comments
 (0)