2626
2727<pre >
2828<strong >输入: </strong >s = "abcabcbb"
29- <strong >输出: </strong >3
29+ <strong >输出: </strong >3
3030<strong >解释:</strong > 因为无重复字符的最长子串是 <code >"abc"</code >,所以其长度为 3。
3131</pre >
3232
@@ -62,26 +62,15 @@ tags:
6262
6363<!-- solution:start -->
6464
65- ### 方法一:双指针 + 哈希表
66-
67- 定义一个哈希表记录当前窗口内出现的字符,记 $i$ 和 $j$ 分别表示不重复子串的开始位置和结束位置,无重复字符子串的最大长度记为 ` ans ` 。
65+ ### 方法一:滑动窗口
6866
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$ 出现的次数 。
7068
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)$ 。
7270
73- 时间复杂度 $O(n)$,其中 $n$ 表示字符串 ` s ` 的长度 。
71+ 最终,我们返回答案 $\textit{ans}$ 即可 。
7472
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$。
8574
8675<!-- tabs:start -->
8776
@@ -90,14 +79,14 @@ for (int i = 0, j = 0; i < n; ++i) {
9079``` python
9180class Solution :
9281 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 )
10190 return ans
10291```
10392
@@ -106,15 +95,15 @@ class Solution:
10695``` java
10796class Solution {
10897 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++ )];
115105 }
116- ss[c] = true ;
117- ans = Math . max(ans, j - i + 1 );
106+ ans = Math . max(ans, r - l + 1 );
118107 }
119108 return ans;
120109 }
@@ -127,14 +116,14 @@ class Solution {
127116class Solution {
128117public:
129118 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++]] ;
135125 }
136- ss[ s[ j]] = true;
137- ans = max(ans, j - i + 1);
126+ ans = max(ans, r - l + 1);
138127 }
139128 return ans;
140129 }
@@ -145,14 +134,15 @@ public:
145134
146135```go
147136func 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++
153144 }
154- ss[s[j]] = true
155- ans = max(ans, j-i+1)
145+ ans = max(ans, r-l+1)
156146 }
157147 return
158148}
@@ -163,13 +153,15 @@ func lengthOfLongestSubstring(s string) (ans int) {
163153``` ts
164154function lengthOfLongestSubstring(s : string ): number {
165155 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 ;
170163 }
171- ss .add (s [j ]);
172- ans = Math .max (ans , j - i + 1 );
164+ ans = Math .max (ans , r - l + 1 );
173165 }
174166 return ans ;
175167}
@@ -178,24 +170,22 @@ function lengthOfLongestSubstring(s: string): number {
178170#### Rust
179171
180172``` rust
181- use std :: collections :: HashSet ;
182-
183173impl Solution {
184174 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
199189 }
200190}
201191```
@@ -209,13 +199,15 @@ impl Solution {
209199 */
210200var lengthOfLongestSubstring = function (s ) {
211201 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;
216209 }
217- ss .add (s[j]);
218- ans = Math .max (ans, j - i + 1 );
210+ ans = Math .max (ans, r - l + 1 );
219211 }
220212 return ans;
221213};
@@ -226,14 +218,15 @@ var lengthOfLongestSubstring = function (s) {
226218``` cs
227219public class Solution {
228220 public int LengthOfLongestSubstring (string s ) {
221+ int n = s .Length ;
229222 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 ++ ]];
234228 }
235- ss .Add (s [j ]);
236- ans = Math .Max (ans , j - i + 1 );
229+ ans = Math .Max (ans , r - l + 1 );
237230 }
238231 return ans ;
239232 }
@@ -244,19 +237,18 @@ public class Solution {
244237
245238``` php
246239class Solution {
247- /**
248- * @param String $s
249- * @return Integer
250- */
251240 function lengthOfLongestSubstring($s) {
241+ $n = strlen($s);
252242 $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++;
257250 }
258- $ss[] = $s[$j];
259- $ans = max($ans, $j - $i + 1);
251+ $ans = max($ans, $r - $l + 1);
260252 }
261253 return $ans;
262254 }
@@ -268,62 +260,40 @@ class Solution {
268260``` swift
269261class Solution {
270262 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
281273 }
282- map[char] = i
283- i += 1
274+ ans = max (ans, r - l + 1 )
284275 }
285- return max (maxLength, i - currentStartingIndex)
276+ return ans
286277 }
287278}
288279```
289280
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-
312281#### Kotlin
313282
314283``` kotlin
315284class Solution {
316285 fun lengthOfLongestSubstring (s : String ): Int {
317- var char_set = BooleanArray (128 )
318- var left = 0
286+ val n = s.length
319287 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++
324295 }
325- char_set[c.code] = true
326- ans = Math .max(ans, right - left + 1 )
296+ ans = Math .max(ans, r - l + 1 )
327297 }
328298 return ans
329299 }
0 commit comments