Skip to content

Commit c37cba6

Browse files
authored
feat: update solutions to lc problem: No.0003 (doocs#3893)
No.0003.Longest Substring Without Repeating Characters
1 parent 7f10b62 commit c37cba6

File tree

14 files changed

+309
-383
lines changed

14 files changed

+309
-383
lines changed

solution/0000-0099/0003.Longest Substring Without Repeating Characters/README.md

+104-134
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ tags:
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
9180
class 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
10796
class 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 {
127116
class Solution {
128117
public:
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
147136
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++
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
164154
function 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-
183173
impl 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
*/
210200
var 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
227219
public 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
246239
class 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
269261
class 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
315284
class 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

Comments
 (0)