Skip to content

Commit 8fbe67c

Browse files
authored
feat: add solutions to lc problem: No.1371 (#3868)
No.1371.Find the Longest Substring Containing Vowels in Even Counts
1 parent 0a3f69a commit 8fbe67c

File tree

7 files changed

+249
-146
lines changed

7 files changed

+249
-146
lines changed

solution/1300-1399/1371.Find the Longest Substring Containing Vowels in Even Counts/README.md

+88-48
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,19 @@ tags:
6464

6565
<!-- solution:start -->
6666

67-
### 方法一
67+
### 方法一:前缀异或 + 数组或哈希表
68+
69+
根据题目描述,如果我们用一个数字表示字符串 $\textit{s}$ 的某个前缀中每个元音字母出现的次数的奇偶性,那么当两个前缀的这个数字相同时,这两个前缀的交集就是一个符合条件的子字符串。
70+
71+
我们可以用一个二进制数的低五位分别表示五个元音字母的奇偶性,其中第 $i$ 位为 $1$ 表示该元音字母在子字符串中出现了奇数次,为 $0$ 表示该元音字母在子字符串中出现了偶数次。
72+
73+
我们用 $\textit{mask}$ 表示这个二进制数,用一个数组或哈希表 $\textit{d}$ 记录每个 $\textit{mask}$ 第一次出现的位置。初始时,我们将 $\textit{d}[0] = -1$,表示空字符串的开始位置为 $-1$。
74+
75+
遍历字符串 $\textit{s}$,如果遇到元音字母,就将 $\textit{mask}$ 的对应位取反。接下来,我们判断 $\textit{mask}$ 是否在之前出现过,如果出现过,那么我们就找到了一个符合条件的子字符串,其长度为当前位置减去 $\textit{mask}$ 上一次出现的位置。否则,我们将 $\textit{mask}$ 的当前位置存入 $\textit{d}$。
76+
77+
遍历结束后,我们就找到了最长的符合条件的子字符串。
78+
79+
时间复杂度 $O(n)$,其中 $n$ 为字符串 $\textit{s}$ 的长度。空间复杂度 $O(1)$。
6880

6981
<!-- tabs:start -->
7082

@@ -73,40 +85,39 @@ tags:
7385
```python
7486
class Solution:
7587
def findTheLongestSubstring(self, s: str) -> int:
76-
pos = [inf] * 32
77-
pos[0] = -1
78-
vowels = 'aeiou'
79-
state = ans = 0
88+
d = {0: -1}
89+
ans = mask = 0
8090
for i, c in enumerate(s):
81-
for j, v in enumerate(vowels):
82-
if c == v:
83-
state ^= 1 << j
84-
ans = max(ans, i - pos[state])
85-
pos[state] = min(pos[state], i)
91+
if c in "aeiou":
92+
mask ^= 1 << (ord(c) - ord("a"))
93+
if mask in d:
94+
j = d[mask]
95+
ans = max(ans, i - j)
96+
else:
97+
d[mask] = i
8698
return ans
8799
```
88100

89101
#### Java
90102

91103
```java
92104
class Solution {
93-
94105
public int findTheLongestSubstring(String s) {
95-
int[] pos = new int[32];
96-
Arrays.fill(pos, Integer.MAX_VALUE);
97-
pos[0] = -1;
98106
String vowels = "aeiou";
99-
int state = 0;
100-
int ans = 0;
101-
for (int i = 0; i < s.length(); ++i) {
102-
char c = s.charAt(i);
107+
int[] d = new int[32];
108+
Arrays.fill(d, 1 << 29);
109+
d[0] = 0;
110+
int ans = 0, mask = 0;
111+
for (int i = 1; i <= s.length(); ++i) {
112+
char c = s.charAt(i - 1);
103113
for (int j = 0; j < 5; ++j) {
104114
if (c == vowels.charAt(j)) {
105-
state ^= (1 << j);
115+
mask ^= 1 << j;
116+
break;
106117
}
107118
}
108-
ans = Math.max(ans, i - pos[state]);
109-
pos[state] = Math.min(pos[state], i);
119+
ans = Math.max(ans, i - d[mask]);
120+
d[mask] = Math.min(d[mask], i);
110121
}
111122
return ans;
112123
}
@@ -119,16 +130,20 @@ class Solution {
119130
class Solution {
120131
public:
121132
int findTheLongestSubstring(string s) {
122-
vector<int> pos(32, INT_MAX);
123-
pos[0] = -1;
124133
string vowels = "aeiou";
125-
int state = 0, ans = 0;
126-
for (int i = 0; i < s.size(); ++i) {
127-
for (int j = 0; j < 5; ++j)
128-
if (s[i] == vowels[j])
129-
state ^= (1 << j);
130-
ans = max(ans, i - pos[state]);
131-
pos[state] = min(pos[state], i);
134+
vector<int> d(32, INT_MAX);
135+
d[0] = 0;
136+
int ans = 0, mask = 0;
137+
for (int i = 1; i <= s.length(); ++i) {
138+
char c = s[i - 1];
139+
for (int j = 0; j < 5; ++j) {
140+
if (c == vowels[j]) {
141+
mask ^= 1 << j;
142+
break;
143+
}
144+
}
145+
ans = max(ans, i - d[mask]);
146+
d[mask] = min(d[mask], i);
132147
}
133148
return ans;
134149
}
@@ -138,24 +153,49 @@ public:
138153
#### Go
139154
140155
```go
141-
func findTheLongestSubstring(s string) int {
142-
pos := make([]int, 32)
143-
for i := range pos {
144-
pos[i] = math.MaxInt32
145-
}
146-
pos[0] = -1
147-
vowels := "aeiou"
148-
state, ans := 0, 0
149-
for i, c := range s {
150-
for j, v := range vowels {
151-
if c == v {
152-
state ^= (1 << j)
153-
}
154-
}
155-
ans = max(ans, i-pos[state])
156-
pos[state] = min(pos[state], i)
157-
}
158-
return ans
156+
func findTheLongestSubstring(s string) (ans int) {
157+
vowels := "aeiou"
158+
d := [32]int{}
159+
for i := range d {
160+
d[i] = 1 << 29
161+
}
162+
d[0] = 0
163+
mask := 0
164+
for i := 1; i <= len(s); i++ {
165+
c := s[i-1]
166+
for j := 0; j < 5; j++ {
167+
if c == vowels[j] {
168+
mask ^= 1 << j
169+
break
170+
}
171+
}
172+
ans = max(ans, i-d[mask])
173+
d[mask] = min(d[mask], i)
174+
}
175+
return
176+
}
177+
```
178+
179+
#### TypeScript
180+
181+
```ts
182+
function findTheLongestSubstring(s: string): number {
183+
const vowels = 'aeiou';
184+
const d: number[] = Array(32).fill(1 << 29);
185+
d[0] = 0;
186+
let [ans, mask] = [0, 0];
187+
for (let i = 1; i <= s.length; i++) {
188+
const c = s[i - 1];
189+
for (let j = 0; j < 5; j++) {
190+
if (c === vowels[j]) {
191+
mask ^= 1 << j;
192+
break;
193+
}
194+
}
195+
ans = Math.max(ans, i - d[mask]);
196+
d[mask] = Math.min(d[mask], i);
197+
}
198+
return ans;
159199
}
160200
```
161201

solution/1300-1399/1371.Find the Longest Substring Containing Vowels in Even Counts/README_EN.md

+88-48
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,19 @@ tags:
6262

6363
<!-- solution:start -->
6464

65-
### Solution 1
65+
### Solution 1: Prefix XOR + Array or Hash Table
66+
67+
According to the problem description, if we use a number to represent the parity of the occurrences of each vowel in a prefix of the string $\textit{s}$, then when two prefixes have the same number, the substring between these two prefixes is a valid substring.
68+
69+
We can use the lower five bits of a binary number to represent the parity of the five vowels, where the $i$-th bit being $1$ means the vowel appears an odd number of times in the substring, and $0$ means it appears an even number of times.
70+
71+
We use $\textit{mask}$ to represent this binary number and use an array or hash table $\textit{d}$ to record the first occurrence of each $\textit{mask}$. Initially, we set $\textit{d}[0] = -1$, indicating that the start position of the empty string is $-1$.
72+
73+
We traverse the string $\textit{s}$, and if we encounter a vowel, we toggle the corresponding bit in $\textit{mask}$. Next, we check if $\textit{mask}$ has appeared before. If it has, we have found a valid substring, and its length is the current position minus the last occurrence of $\textit{mask}$. Otherwise, we store the current position of $\textit{mask}$ in $\textit{d}$.
74+
75+
After traversing the string, we will have found the longest valid substring.
76+
77+
The time complexity is $O(n)$, where $n$ is the length of the string $\textit{s}$. The space complexity is $O(1)$.
6678

6779
<!-- tabs:start -->
6880

@@ -71,40 +83,39 @@ tags:
7183
```python
7284
class Solution:
7385
def findTheLongestSubstring(self, s: str) -> int:
74-
pos = [inf] * 32
75-
pos[0] = -1
76-
vowels = 'aeiou'
77-
state = ans = 0
86+
d = {0: -1}
87+
ans = mask = 0
7888
for i, c in enumerate(s):
79-
for j, v in enumerate(vowels):
80-
if c == v:
81-
state ^= 1 << j
82-
ans = max(ans, i - pos[state])
83-
pos[state] = min(pos[state], i)
89+
if c in "aeiou":
90+
mask ^= 1 << (ord(c) - ord("a"))
91+
if mask in d:
92+
j = d[mask]
93+
ans = max(ans, i - j)
94+
else:
95+
d[mask] = i
8496
return ans
8597
```
8698

8799
#### Java
88100

89101
```java
90102
class Solution {
91-
92103
public int findTheLongestSubstring(String s) {
93-
int[] pos = new int[32];
94-
Arrays.fill(pos, Integer.MAX_VALUE);
95-
pos[0] = -1;
96104
String vowels = "aeiou";
97-
int state = 0;
98-
int ans = 0;
99-
for (int i = 0; i < s.length(); ++i) {
100-
char c = s.charAt(i);
105+
int[] d = new int[32];
106+
Arrays.fill(d, 1 << 29);
107+
d[0] = 0;
108+
int ans = 0, mask = 0;
109+
for (int i = 1; i <= s.length(); ++i) {
110+
char c = s.charAt(i - 1);
101111
for (int j = 0; j < 5; ++j) {
102112
if (c == vowels.charAt(j)) {
103-
state ^= (1 << j);
113+
mask ^= 1 << j;
114+
break;
104115
}
105116
}
106-
ans = Math.max(ans, i - pos[state]);
107-
pos[state] = Math.min(pos[state], i);
117+
ans = Math.max(ans, i - d[mask]);
118+
d[mask] = Math.min(d[mask], i);
108119
}
109120
return ans;
110121
}
@@ -117,16 +128,20 @@ class Solution {
117128
class Solution {
118129
public:
119130
int findTheLongestSubstring(string s) {
120-
vector<int> pos(32, INT_MAX);
121-
pos[0] = -1;
122131
string vowels = "aeiou";
123-
int state = 0, ans = 0;
124-
for (int i = 0; i < s.size(); ++i) {
125-
for (int j = 0; j < 5; ++j)
126-
if (s[i] == vowels[j])
127-
state ^= (1 << j);
128-
ans = max(ans, i - pos[state]);
129-
pos[state] = min(pos[state], i);
132+
vector<int> d(32, INT_MAX);
133+
d[0] = 0;
134+
int ans = 0, mask = 0;
135+
for (int i = 1; i <= s.length(); ++i) {
136+
char c = s[i - 1];
137+
for (int j = 0; j < 5; ++j) {
138+
if (c == vowels[j]) {
139+
mask ^= 1 << j;
140+
break;
141+
}
142+
}
143+
ans = max(ans, i - d[mask]);
144+
d[mask] = min(d[mask], i);
130145
}
131146
return ans;
132147
}
@@ -136,24 +151,49 @@ public:
136151
#### Go
137152
138153
```go
139-
func findTheLongestSubstring(s string) int {
140-
pos := make([]int, 32)
141-
for i := range pos {
142-
pos[i] = math.MaxInt32
143-
}
144-
pos[0] = -1
145-
vowels := "aeiou"
146-
state, ans := 0, 0
147-
for i, c := range s {
148-
for j, v := range vowels {
149-
if c == v {
150-
state ^= (1 << j)
151-
}
152-
}
153-
ans = max(ans, i-pos[state])
154-
pos[state] = min(pos[state], i)
155-
}
156-
return ans
154+
func findTheLongestSubstring(s string) (ans int) {
155+
vowels := "aeiou"
156+
d := [32]int{}
157+
for i := range d {
158+
d[i] = 1 << 29
159+
}
160+
d[0] = 0
161+
mask := 0
162+
for i := 1; i <= len(s); i++ {
163+
c := s[i-1]
164+
for j := 0; j < 5; j++ {
165+
if c == vowels[j] {
166+
mask ^= 1 << j
167+
break
168+
}
169+
}
170+
ans = max(ans, i-d[mask])
171+
d[mask] = min(d[mask], i)
172+
}
173+
return
174+
}
175+
```
176+
177+
#### TypeScript
178+
179+
```ts
180+
function findTheLongestSubstring(s: string): number {
181+
const vowels = 'aeiou';
182+
const d: number[] = Array(32).fill(1 << 29);
183+
d[0] = 0;
184+
let [ans, mask] = [0, 0];
185+
for (let i = 1; i <= s.length; i++) {
186+
const c = s[i - 1];
187+
for (let j = 0; j < 5; j++) {
188+
if (c === vowels[j]) {
189+
mask ^= 1 << j;
190+
break;
191+
}
192+
}
193+
ans = Math.max(ans, i - d[mask]);
194+
d[mask] = Math.min(d[mask], i);
195+
}
196+
return ans;
157197
}
158198
```
159199

Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
class Solution {
22
public:
33
int findTheLongestSubstring(string s) {
4-
vector<int> pos(32, INT_MAX);
5-
pos[0] = -1;
64
string vowels = "aeiou";
7-
int state = 0, ans = 0;
8-
for (int i = 0; i < s.size(); ++i) {
9-
for (int j = 0; j < 5; ++j)
10-
if (s[i] == vowels[j])
11-
state ^= (1 << j);
12-
ans = max(ans, i - pos[state]);
13-
pos[state] = min(pos[state], i);
5+
vector<int> d(32, INT_MAX);
6+
d[0] = 0;
7+
int ans = 0, mask = 0;
8+
for (int i = 1; i <= s.length(); ++i) {
9+
char c = s[i - 1];
10+
for (int j = 0; j < 5; ++j) {
11+
if (c == vowels[j]) {
12+
mask ^= 1 << j;
13+
break;
14+
}
15+
}
16+
ans = max(ans, i - d[mask]);
17+
d[mask] = min(d[mask], i);
1418
}
1519
return ans;
1620
}
17-
};
21+
};

0 commit comments

Comments
 (0)