Skip to content

Commit db780ce

Browse files
committed
feat: add solutions to lcof problem: No.48
1 parent 656d42b commit db780ce

File tree

8 files changed

+126
-141
lines changed

8 files changed

+126
-141
lines changed

lcof/面试题48. 最长不含重复字符的子字符串/README.md

+73-81
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@
4040

4141
## 解法
4242

43-
“滑动窗口 + 哈希表”。
43+
**方法一:双指针 + 哈希表**
4444

45-
定义一个哈希表记录当前窗口内出现的字符,i、j 分别表示不重复子串的结束位置和开始位置,res 表示无重复字符子串的最大长度
45+
我们用双指针 $j$ 和 $i$ 分别表示子串的左右边界,其中 $j$ 是滑动窗口的左边界,$i$ 是滑动窗口的右边界,用哈希表 $vis$ 记录每个字符是否出现过
4646

47-
遍历 i,若 `[j, i - 1]` 窗口内存在 `s[i]`,则 j 循环向右移动,更新哈希表,直至 `[j, i - 1]` 窗口不存在 `s[i]`,循环结束。将 `s[i]` 加入哈希表中,此时 `[j, i]` 窗口内不含重复元素,更新 res 的最大值:`res = max(res, i - j + 1)`
47+
遍历字符串 $s$,如果此时 $s[i]$ 在哈希表 $vis$ 中存在,说明 $s[i]$ 重复了,我们需要将左边界 $j$ 右移,直到 $s[i]$ 不在哈希表 $vis$ 中为止,然后将 $s[i]$ 加入哈希表 $vis$ 中。此时,我们更新无重复字符子串的最大长度,即 $ans = max(ans, i - j + 1)$
4848

49-
最后返回 res 即可。
49+
遍历结束后,我们返回 $ans$ 即可。
50+
51+
时间复杂度 $O(n)$,空间复杂度 $O(C)$。其中 $n$ 是字符串 $s$ 的长度;而 $C$ 是字符集的大小。
5052

5153
<!-- tabs:start -->
5254

@@ -55,35 +57,46 @@
5557
```python
5658
class Solution:
5759
def lengthOfLongestSubstring(self, s: str) -> int:
58-
i = j = res = 0
59-
chars = set()
60-
while i < len(s):
61-
while s[i] in chars:
62-
if s[j] in chars:
63-
chars.remove(s[j])
60+
cnt = Counter()
61+
ans = j = 0
62+
for i, c in enumerate(s):
63+
cnt[c] += 1
64+
while cnt[c] > 1:
65+
cnt[s[j]] -= 1
6466
j += 1
65-
chars.add(s[i])
66-
res = max(res, i - j + 1)
67-
i += 1
68-
return res
67+
ans = max(ans, i - j + 1)
68+
return ans
69+
```
70+
71+
```python
72+
class Solution:
73+
def lengthOfLongestSubstring(self, s: str) -> int:
74+
vis = set()
75+
ans = j = 0
76+
for i, c in enumerate(s):
77+
while c in vis:
78+
vis.remove(s[j])
79+
j += 1
80+
vis.add(c)
81+
ans = max(ans, i - j + 1)
82+
return ans
6983
```
7084

7185
### **Java**
7286

7387
```java
7488
class Solution {
7589
public int lengthOfLongestSubstring(String s) {
76-
int res = 0;
77-
Set<Character> set = new HashSet<>();
78-
for (int i = 0, j = 0; i < s.length(); ++i) {
79-
char c = s.charAt(i);
80-
while (set.contains(c)) {
81-
set.remove(s.charAt(j++));
90+
int ans = 0, j = 0;
91+
Set<Character> vis = new HashSet<>();
92+
for (int i = 0; i < s.length(); ++i) {
93+
while (vis.contains(s.charAt(i))) {
94+
vis.remove(s.charAt(j++));
8295
}
83-
set.add(c);
84-
res = Math.max(res, i - j + 1);
96+
vis.add(s.charAt(i));
97+
ans = Math.max(ans, i - j + 1);
8598
}
86-
return res;
99+
return ans;
87100
}
88101
}
89102
```
@@ -94,35 +107,35 @@ class Solution {
94107
class Solution {
95108
public:
96109
int lengthOfLongestSubstring(string s) {
97-
int res = 0;
98-
unordered_set<char> chars;
110+
int ans = 0;
111+
unordered_set<char> vis;
99112
for (int i = 0, j = 0; i < s.size(); ++i) {
100-
while (chars.count(s[i])) {
101-
chars.erase(s[j++]);
113+
while (vis.count(s[i])) {
114+
vis.erase(s[j++]);
102115
}
103-
chars.insert(s[i]);
104-
res = max(res, i - j + 1);
116+
vis.insert(s[i]);
117+
ans = max(ans, i - j + 1);
105118
}
106-
return res;
119+
return ans;
107120
}
108121
};
109122
```
110123
111124
### **Go**
112125
113126
```go
114-
func lengthOfLongestSubstring(s string) int {
115-
chars := make(map[byte]bool)
116-
res := 0
117-
for i, j := 0, 0; i < len(s); i++ {
118-
for chars[s[i]] {
119-
chars[s[j]] = false
127+
func lengthOfLongestSubstring(s string) (ans int) {
128+
vis := map[byte]bool{}
129+
j := 0
130+
for i := range s {
131+
for vis[s[i]] {
132+
vis[s[j]] = false
120133
j++
121134
}
122-
chars[s[i]] = true
123-
res = max(res, i-j+1)
135+
vis[s[i]] = true
136+
ans = max(ans, i-j+1)
124137
}
125-
return res
138+
return
126139
}
127140
128141
func max(a, b int) int {
@@ -141,53 +154,33 @@ func max(a, b int) int {
141154
* @return {number}
142155
*/
143156
var lengthOfLongestSubstring = function (s) {
144-
let res = 0;
145-
let chars = new Set();
157+
let ans = 0;
158+
let vis = new Set();
146159
for (let i = 0, j = 0; i < s.length; ++i) {
147-
while (chars.has(s[i])) {
148-
chars.delete(s[j++]);
160+
while (vis.has(s[i])) {
161+
vis.delete(s[j++]);
149162
}
150-
chars.add(s[i]);
151-
res = Math.max(res, i - j + 1);
163+
vis.add(s[i]);
164+
ans = Math.max(ans, i - j + 1);
152165
}
153-
return res;
166+
return ans;
154167
};
155168
```
156169

157170
### **TypeScript**
158171

159172
```ts
160173
function lengthOfLongestSubstring(s: string): number {
161-
const n = s.length;
162-
const set = new Set<string>();
163-
let res = 0;
164-
let i = 0;
165-
for (let j = 0; j < n; j++) {
166-
const c = s[j];
167-
while (set.has(c)) {
168-
set.delete(s[i++]);
169-
}
170-
set.add(c);
171-
res = Math.max(res, set.size);
172-
}
173-
return res;
174-
}
175-
```
176-
177-
```ts
178-
function lengthOfLongestSubstring(s: string): number {
179-
const map = new Map<string, number>();
180-
const n = s.length;
181-
let res = 0;
182-
let i = -1;
183-
for (let j = 0; j < n; j++) {
184-
if (map.has(s[j])) {
185-
i = Math.max(i, map.get(s[j]));
174+
let ans = 0;
175+
let vis = new Set<string>();
176+
for (let i = 0, j = 0; i < s.length; ++i) {
177+
while (vis.has(s[i])) {
178+
vis.delete(s[j++]);
186179
}
187-
map.set(s[j], j);
188-
res = Math.max(res, j - i);
180+
vis.add(s[i]);
181+
ans = Math.max(ans, i - j + 1);
189182
}
190-
return res;
183+
return ans;
191184
}
192185
```
193186

@@ -243,15 +236,14 @@ impl Solution {
243236
```cs
244237
public class Solution {
245238
public int LengthOfLongestSubstring(string s) {
246-
var set = new HashSet<char>();
239+
var vis = new HashSet<char>();
247240
int ans = 0;
248-
for (int l=0, r=0; r < s.Length; r++) {
249-
while (set.Contains(s[r]))
250-
{
251-
set.Remove(s[l++]);
241+
for (int i = 0, j = 0; i < s.Length; ++i) {
242+
while (vis.Contains(s[i])) {
243+
vis.Remove(s[j++]);
252244
}
253-
ans = Math.Max(r - l + 1, ans);
254-
set.Add(s[r]);
245+
vis.Add(s[i]);
246+
ans = Math.Max(ans, i - j + 1);
255247
}
256248
return ans;
257249
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
class Solution {
22
public:
33
int lengthOfLongestSubstring(string s) {
4-
int res = 0;
5-
unordered_set<char> chars;
4+
int ans = 0;
5+
unordered_set<char> vis;
66
for (int i = 0, j = 0; i < s.size(); ++i) {
7-
while (chars.count(s[i])) {
8-
chars.erase(s[j++]);
7+
while (vis.count(s[i])) {
8+
vis.erase(s[j++]);
99
}
10-
chars.insert(s[i]);
11-
res = max(res, i - j + 1);
10+
vis.insert(s[i]);
11+
ans = max(ans, i - j + 1);
1212
}
13-
return res;
13+
return ans;
1414
}
1515
};

lcof/面试题48. 最长不含重复字符的子字符串/Solution.cs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
public class Solution {
22
public int LengthOfLongestSubstring(string s) {
3-
var set = new HashSet<char>();
3+
var vis = new HashSet<char>();
44
int ans = 0;
5-
for (int l=0, r=0; r < s.Length; r++) {
6-
while (set.Contains(s[r]))
7-
{
8-
set.Remove(s[l++]);
5+
for (int i = 0, j = 0; i < s.Length; ++i) {
6+
while (vis.Contains(s[i])) {
7+
vis.Remove(s[j++]);
98
}
10-
ans = Math.Max(r - l + 1, ans);
11-
set.Add(s[r]);
9+
vis.Add(s[i]);
10+
ans = Math.Max(ans, i - j + 1);
1211
}
1312
return ans;
1413
}

lcof/面试题48. 最长不含重复字符的子字符串/Solution.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
func lengthOfLongestSubstring(s string) int {
2-
chars := make(map[byte]bool)
3-
res := 0
4-
for i, j := 0, 0; i < len(s); i++ {
5-
for chars[s[i]] {
6-
chars[s[j]] = false
1+
func lengthOfLongestSubstring(s string) (ans int) {
2+
vis := map[byte]bool{}
3+
j := 0
4+
for i := range s {
5+
for vis[s[i]] {
6+
vis[s[j]] = false
77
j++
88
}
9-
chars[s[i]] = true
10-
res = max(res, i-j+1)
9+
vis[s[i]] = true
10+
ans = max(ans, i-j+1)
1111
}
12-
return res
12+
return
1313
}
1414

1515
func max(a, b int) int {
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
class Solution {
22
public int lengthOfLongestSubstring(String s) {
3-
int res = 0;
4-
Set<Character> set = new HashSet<>();
5-
for (int i = 0, j = 0; i < s.length(); ++i) {
6-
char c = s.charAt(i);
7-
while (set.contains(c)) {
8-
set.remove(s.charAt(j++));
3+
int ans = 0, j = 0;
4+
Set<Character> vis = new HashSet<>();
5+
for (int i = 0; i < s.length(); ++i) {
6+
while (vis.contains(s.charAt(i))) {
7+
vis.remove(s.charAt(j++));
98
}
10-
set.add(c);
11-
res = Math.max(res, i - j + 1);
9+
vis.add(s.charAt(i));
10+
ans = Math.max(ans, i - j + 1);
1211
}
13-
return res;
12+
return ans;
1413
}
1514
}

lcof/面试题48. 最长不含重复字符的子字符串/Solution.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
* @return {number}
44
*/
55
var lengthOfLongestSubstring = function (s) {
6-
let res = 0;
7-
let chars = new Set();
6+
let ans = 0;
7+
let vis = new Set();
88
for (let i = 0, j = 0; i < s.length; ++i) {
9-
while (chars.has(s[i])) {
10-
chars.delete(s[j++]);
9+
while (vis.has(s[i])) {
10+
vis.delete(s[j++]);
1111
}
12-
chars.add(s[i]);
13-
res = Math.max(res, i - j + 1);
12+
vis.add(s[i]);
13+
ans = Math.max(ans, i - j + 1);
1414
}
15-
return res;
15+
return ans;
1616
};
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
class Solution:
22
def lengthOfLongestSubstring(self, s: str) -> int:
3-
i = j = res = 0
4-
chars = set()
5-
while i < len(s):
6-
while s[i] in chars:
7-
if s[j] in chars:
8-
chars.remove(s[j])
3+
vis = set()
4+
ans = j = 0
5+
for i, c in enumerate(s):
6+
while c in vis:
7+
vis.remove(s[j])
98
j += 1
10-
chars.add(s[i])
11-
res = max(res, i - j + 1)
12-
i += 1
13-
return res
9+
vis.add(c)
10+
ans = max(ans, i - j + 1)
11+
return ans
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
function lengthOfLongestSubstring(s: string): number {
2-
const n = s.length;
3-
const set = new Set<string>();
4-
let res = 0;
5-
let i = 0;
6-
for (let j = 0; j < n; j++) {
7-
const c = s[j];
8-
while (set.has(c)) {
9-
set.delete(s[i++]);
2+
let ans = 0;
3+
let vis = new Set<string>();
4+
for (let i = 0, j = 0; i < s.length; ++i) {
5+
while (vis.has(s[i])) {
6+
vis.delete(s[j++]);
107
}
11-
set.add(c);
12-
res = Math.max(res, set.size);
8+
vis.add(s[i]);
9+
ans = Math.max(ans, i - j + 1);
1310
}
14-
return res;
11+
return ans;
1512
}

0 commit comments

Comments
 (0)