26
26
27
27
<pre >
28
28
<strong >输入: </strong >s = "abcabcbb"
29
- <strong >输出: </strong >3
29
+ <strong >输出: </strong >3
30
30
<strong >解释:</strong > 因为无重复字符的最长子串是 <code >"abc"</code >,所以其长度为 3。
31
31
</pre >
32
32
@@ -62,26 +62,15 @@ tags:
62
62
63
63
<!-- solution:start -->
64
64
65
- ### 方法一:双指针 + 哈希表
66
-
67
- 定义一个哈希表记录当前窗口内出现的字符,记 $i$ 和 $j$ 分别表示不重复子串的开始位置和结束位置,无重复字符子串的最大长度记为 ` ans ` 。
65
+ ### 方法一:滑动窗口
68
66
69
- 遍历字符串 ` s ` 的每个字符 $s [ j ] $,我们记为 $c$。若 $s [ i..j-1 ] $ 窗口内存在 $c$,则 $i$ 循环向右移动,更新哈希表,直至 $s [ i..j-1 ] $ 窗口不存在 ` c ` ,循环结束。将 ` c ` 加入哈希表中,此时 $s [ i..j ] $ 窗口内不含重复元素,更新 ` ans ` 的最大值 。
67
+ 我们可以用两个指针 $l$ 和 $r$ 维护一个滑动窗口,使其始终满足窗口内没有重复字符,初始时 $l$ 和 $r$ 都指向字符串的第一个字符。用一个哈希表或者长度为 $128$ 的数组 $\textit{cnt}$ 来记录每个字符出现的次数,其中 $\textit{cnt} [ c ] $ 表示字符 $c$ 出现的次数 。
70
68
71
- 最后返回 ` ans ` 即可 。
69
+ 接下来,我们依次移动右指针 $r$,每次移动时,将 $\textit{cnt} [ s [ r ]] $ 的值加 $1$,然后判断当前窗口 $ [ l, r ] $ 内 $\textit{cnt} [ s [ r ]] $ 是否大于 $1$,如果大于 $1$,说明当前窗口内有重复字符,我们需要移动左指针 $l$,直到窗口内没有重复字符为止。然后,我们更新答案 $\textit{ ans} = \max(\textit{ans}, r - l + 1)$ 。
72
70
73
- 时间复杂度 $O(n)$,其中 $n$ 表示字符串 ` s ` 的长度 。
71
+ 最终,我们返回答案 $\textit{ans}$ 即可 。
74
72
75
- 双指针算法模板:
76
-
77
- ``` java
78
- for (int i = 0 , j = 0 ; i < n; ++ i) {
79
- while (j < i && check(j, i)) {
80
- ++ j;
81
- }
82
- // 具体问题的逻辑
83
- }
84
- ```
73
+ 时间复杂度 $O(n)$,其中 $n$ 为字符串的长度。空间复杂度 $O(|\Sigma|)$,其中 $\Sigma$ 表示字符集,这里 $\Sigma$ 的大小为 $128$。
85
74
86
75
<!-- tabs:start -->
87
76
@@ -90,14 +79,14 @@ for (int i = 0, j = 0; i < n; ++i) {
90
79
``` python
91
80
class Solution :
92
81
def lengthOfLongestSubstring (self , s : str ) -> int :
93
- ss = set ()
94
- ans = i = 0
95
- for j , c in enumerate (s):
96
- while c in ss:
97
- ss.remove(s[i])
98
- i + = 1
99
- ss.add(c)
100
- ans = max (ans, j - i + 1 )
82
+ cnt = Counter ()
83
+ ans = l = 0
84
+ for r , c in enumerate (s):
85
+ cnt[c] += 1
86
+ while cnt[c] > 1 :
87
+ cnt[s[l]] - = 1
88
+ l += 1
89
+ ans = max (ans, r - l + 1 )
101
90
return ans
102
91
```
103
92
@@ -106,15 +95,15 @@ class Solution:
106
95
``` java
107
96
class Solution {
108
97
public int lengthOfLongestSubstring (String s ) {
109
- boolean [] ss = new boolean [128 ];
110
- int ans = 0 ;
111
- for (int i = 0 , j = 0 ; j < s. length(); ++ j) {
112
- char c = s. charAt(j);
113
- while (ss[c]) {
114
- ss[s. charAt(i++ )] = false ;
98
+ int [] cnt = new int [128 ];
99
+ int ans = 0 , n = s. length();
100
+ for (int l = 0 , r = 0 ; r < n; ++ r) {
101
+ char c = s. charAt(r);
102
+ ++ cnt[c];
103
+ while (cnt[c] > 1 ) {
104
+ -- cnt[s. charAt(l++ )];
115
105
}
116
- ss[c] = true ;
117
- ans = Math . max(ans, j - i + 1 );
106
+ ans = Math . max(ans, r - l + 1 );
118
107
}
119
108
return ans;
120
109
}
@@ -127,14 +116,14 @@ class Solution {
127
116
class Solution {
128
117
public:
129
118
int lengthOfLongestSubstring(string s) {
130
- bool ss[ 128] {};
131
- int ans = 0;
132
- for (int i = 0, j = 0; j < s.size(); ++j) {
133
- while (ss[ s[ j]] ) {
134
- ss[ s[ i++]] = false;
119
+ int cnt[ 128] {};
120
+ int ans = 0, n = s.size();
121
+ for (int l = 0, r = 0; r < n; ++r) {
122
+ ++cnt[ s[ r]] ;
123
+ while (cnt[ s[ r]] > 1) {
124
+ --cnt[ s[ l++]] ;
135
125
}
136
- ss[ s[ j]] = true;
137
- ans = max(ans, j - i + 1);
126
+ ans = max(ans, r - l + 1);
138
127
}
139
128
return ans;
140
129
}
@@ -145,14 +134,15 @@ public:
145
134
146
135
```go
147
136
func lengthOfLongestSubstring(s string) (ans int) {
148
- ss := [128]bool{}
149
- for i, j := 0, 0; j < len(s); j++ {
150
- for ss[s[j]] {
151
- ss[s[i]] = false
152
- i++
137
+ cnt := [128]int{}
138
+ l := 0
139
+ for r, c := range s {
140
+ cnt[c]++
141
+ for cnt[c] > 1 {
142
+ cnt[s[l]]--
143
+ l++
153
144
}
154
- ss[s[j]] = true
155
- ans = max(ans, j-i+1)
145
+ ans = max(ans, r-l+1)
156
146
}
157
147
return
158
148
}
@@ -163,13 +153,15 @@ func lengthOfLongestSubstring(s string) (ans int) {
163
153
``` ts
164
154
function lengthOfLongestSubstring(s : string ): number {
165
155
let ans = 0 ;
166
- const ss: Set <string > = new Set ();
167
- for (let i = 0 , j = 0 ; j < s .length ; ++ j ) {
168
- while (ss .has (s [j ])) {
169
- ss .delete (s [i ++ ]);
156
+ const cnt = new Map <string , number >();
157
+ const n = s .length ;
158
+ for (let l = 0 , r = 0 ; r < n ; ++ r ) {
159
+ cnt .set (s [r ], (cnt .get (s [r ]) || 0 ) + 1 );
160
+ while (cnt .get (s [r ])! > 1 ) {
161
+ cnt .set (s [l ], cnt .get (s [l ])! - 1 );
162
+ ++ l ;
170
163
}
171
- ss .add (s [j ]);
172
- ans = Math .max (ans , j - i + 1 );
164
+ ans = Math .max (ans , r - l + 1 );
173
165
}
174
166
return ans ;
175
167
}
@@ -178,24 +170,22 @@ function lengthOfLongestSubstring(s: string): number {
178
170
#### Rust
179
171
180
172
``` rust
181
- use std :: collections :: HashSet ;
182
-
183
173
impl Solution {
184
174
pub fn length_of_longest_substring (s : String ) -> i32 {
185
- let s = s . as_bytes () ;
186
- let mut ss = HashSet :: new () ;
187
- let mut i = 0 ;
188
- s . iter ()
189
- . map ( | c | {
190
- while ss . contains ( & c ) {
191
- ss . remove ( & s [ i ]) ;
192
- i += 1 ;
193
- }
194
- ss . insert ( c ) ;
195
- ss . len ()
196
- })
197
- . max ()
198
- . unwrap_or ( 0 ) as i32
175
+ let mut cnt = [ 0 ; 128 ] ;
176
+ let mut ans = 0 ;
177
+ let mut l = 0 ;
178
+ let chars : Vec < char > = s . chars () . collect ();
179
+ let n = chars . len ();
180
+ for ( r , & c ) in chars . iter () . enumerate ( ) {
181
+ cnt [ c as usize ] += 1 ;
182
+ while cnt [ c as usize ] > 1 {
183
+ cnt [ chars [ l ] as usize ] -= 1 ;
184
+ l += 1 ;
185
+ }
186
+ ans = ans . max (( r - l + 1 ) as i32 );
187
+ }
188
+ ans
199
189
}
200
190
}
201
191
```
@@ -209,13 +199,15 @@ impl Solution {
209
199
*/
210
200
var lengthOfLongestSubstring = function (s ) {
211
201
let ans = 0 ;
212
- const ss = new Set ();
213
- for (let i = 0 , j = 0 ; j < s .length ; ++ j) {
214
- while (ss .has (s[j])) {
215
- ss .delete (s[i++ ]);
202
+ const n = s .length ;
203
+ const cnt = new Map ();
204
+ for (let l = 0 , r = 0 ; r < n; ++ r) {
205
+ cnt .set (s[r], (cnt .get (s[r]) || 0 ) + 1 );
206
+ while (cnt .get (s[r]) > 1 ) {
207
+ cnt .set (s[l], cnt .get (s[l]) - 1 );
208
+ ++ l;
216
209
}
217
- ss .add (s[j]);
218
- ans = Math .max (ans, j - i + 1 );
210
+ ans = Math .max (ans, r - l + 1 );
219
211
}
220
212
return ans;
221
213
};
@@ -226,14 +218,15 @@ var lengthOfLongestSubstring = function (s) {
226
218
``` cs
227
219
public class Solution {
228
220
public int LengthOfLongestSubstring (string s ) {
221
+ int n = s .Length ;
229
222
int ans = 0 ;
230
- var ss = new HashSet <char >();
231
- for (int i = 0 , j = 0 ; j < s .Length ; ++ j ) {
232
- while (ss .Contains (s [j ])) {
233
- ss .Remove (s [i ++ ]);
223
+ var cnt = new int [128 ];
224
+ for (int l = 0 , r = 0 ; r < n ; ++ r ) {
225
+ ++ cnt [s [r ]];
226
+ while (cnt [s [r ]] > 1 ) {
227
+ -- cnt [s [l ++ ]];
234
228
}
235
- ss .Add (s [j ]);
236
- ans = Math .Max (ans , j - i + 1 );
229
+ ans = Math .Max (ans , r - l + 1 );
237
230
}
238
231
return ans ;
239
232
}
@@ -244,19 +237,18 @@ public class Solution {
244
237
245
238
``` php
246
239
class Solution {
247
- /**
248
- * @param String $s
249
- * @return Integer
250
- */
251
240
function lengthOfLongestSubstring($s) {
241
+ $n = strlen($s);
252
242
$ans = 0;
253
- $ss = [];
254
- for ($i = 0, $j = 0; $j < strlen($s); ++$j) {
255
- while (in_array($s[$j], $ss)) {
256
- unset($ss[array_search($s[$i++], $ss)]);
243
+ $cnt = array_fill(0, 128, 0);
244
+ $l = 0;
245
+ for ($r = 0; $r < $n; ++$r) {
246
+ $cnt[ord($s[$r])]++;
247
+ while ($cnt[ord($s[$r])] > 1) {
248
+ $cnt[ord($s[$l])]--;
249
+ $l++;
257
250
}
258
- $ss[] = $s[$j];
259
- $ans = max($ans, $j - $i + 1);
251
+ $ans = max($ans, $r - $l + 1);
260
252
}
261
253
return $ans;
262
254
}
@@ -268,62 +260,40 @@ class Solution {
268
260
``` swift
269
261
class Solution {
270
262
func lengthOfLongestSubstring (_ s : String ) -> Int {
271
- var map = [ Character : Int ]()
272
- var currentStartingIndex = 0
273
- var i = 0
274
- var maxLength = 0
275
- for char in s {
276
- if map[char] != nil {
277
- if map[char] ! >= currentStartingIndex {
278
- maxLength = max (maxLength, i - currentStartingIndex)
279
- currentStartingIndex = map[char] ! + 1
280
- }
263
+ let n = s. count
264
+ var ans = 0
265
+ var cnt = [ Int ]( repeating : 0 , count : 128 )
266
+ var l = 0
267
+ let sArray = Array (s)
268
+ for r in 0 ..< n {
269
+ cnt[ Int (sArray[r]. asciiValue ! )] += 1
270
+ while cnt[ Int (sArray[r]. asciiValue ! )] > 1 {
271
+ cnt[ Int (sArray[l]. asciiValue ! )] -= 1
272
+ l += 1
281
273
}
282
- map[char] = i
283
- i += 1
274
+ ans = max (ans, r - l + 1 )
284
275
}
285
- return max (maxLength, i - currentStartingIndex)
276
+ return ans
286
277
}
287
278
}
288
279
```
289
280
290
- #### Nim
291
-
292
- ``` nim
293
- proc lengthOfLongestSubstring(s: string): int =
294
- var
295
- i = 0
296
- j = 0
297
- res = 0
298
- literals: set[char] = {}
299
-
300
- while i < s.len:
301
- while s[i] in literals:
302
- if s[j] in literals:
303
- excl(literals, s[j])
304
- j += 1
305
- literals.incl(s[i]) # Uniform Function Call Syntax f(x) = x.f
306
- res = max(res, i - j + 1)
307
- i += 1
308
-
309
- result = res # result has the default return value
310
- ```
311
-
312
281
#### Kotlin
313
282
314
283
``` kotlin
315
284
class Solution {
316
285
fun lengthOfLongestSubstring (s : String ): Int {
317
- var char_set = BooleanArray (128 )
318
- var left = 0
286
+ val n = s.length
319
287
var ans = 0
320
- s.forEachIndexed { right, c ->
321
- while (char_set[c.code]) {
322
- char_set[s[left].code] = false
323
- left++
288
+ val cnt = IntArray (128 )
289
+ var l = 0
290
+ for (r in 0 until n) {
291
+ cnt[s[r].toInt()]++
292
+ while (cnt[s[r].toInt()] > 1 ) {
293
+ cnt[s[l].toInt()]--
294
+ l++
324
295
}
325
- char_set[c.code] = true
326
- ans = Math .max(ans, right - left + 1 )
296
+ ans = Math .max(ans, r - l + 1 )
327
297
}
328
298
return ans
329
299
}
0 commit comments