Skip to content

Commit c8c1c33

Browse files
committed
fix
1 parent 9959dbd commit c8c1c33

File tree

4 files changed

+233
-0
lines changed

4 files changed

+233
-0
lines changed

code/Leetcode25/LeetCode25.java

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import com.sun.istack.internal.Nullable;
2+
3+
import java.util.HashSet;
4+
import java.util.LinkedHashSet;
5+
import java.util.Set;
6+
7+
public class LeetCode25 {
8+
public static void main(String[] args) {
9+
LeetCode25 test = new LeetCode25();
10+
11+
System.out.println("abcabcbb:" + test.longestSubStringSlidingWindow("abcabcbb"));
12+
System.out.println("bbbbb:" + test.longestSubStringSlidingWindow("bbbbb"));
13+
System.out.println("pwwkew:" + test.longestSubStringSlidingWindow("pwwkew"));
14+
System.out.println("pwwkew:" + test.longestSubStringSlidingWindow("powkew"));
15+
16+
}
17+
18+
@Nullable
19+
public String longestSubStringSlidingWindow(@Nullable String s) {
20+
if (s == null || s.length() == 0) {
21+
return null;
22+
}
23+
24+
int maxLength = 0;
25+
int resultIndex = 0;
26+
27+
Set<Character> set = new LinkedHashSet<>();
28+
29+
int length = s.length();
30+
int i = 0, j = 0;
31+
32+
while (i < length && j < length) {
33+
34+
if (set.contains(s.charAt(j))) {
35+
set.remove(s.charAt(i));
36+
37+
i++;
38+
continue;
39+
}
40+
41+
set.add(s.charAt(j));
42+
43+
int newLength = j - i + 1;
44+
if (newLength > maxLength) {
45+
maxLength = newLength;
46+
resultIndex = i;
47+
}
48+
49+
j++;
50+
}
51+
52+
return maxLength == 0 ? null : s.substring(resultIndex, resultIndex + maxLength);
53+
}
54+
55+
@Nullable
56+
public String longestSubString(@Nullable String s) {
57+
if (s == null || s.length() == 0) {
58+
return null;
59+
}
60+
61+
int maxLength = 0;
62+
int resultIndex = 0;
63+
64+
int n = s.length();
65+
66+
for (int i = 0; i < n; i++) {
67+
for (int j = i; j < n; j++) {
68+
if (hasDuplicateChar(s, i, j)) {
69+
break;
70+
}
71+
72+
int newLength = j - i + 1;
73+
if (newLength <= maxLength) {
74+
continue;
75+
}
76+
77+
78+
maxLength = newLength;
79+
resultIndex = i;
80+
}
81+
}
82+
83+
return maxLength == 0 ? null : s.substring(resultIndex, resultIndex + maxLength);
84+
}
85+
86+
private boolean hasDuplicateChar(String subStr, int start, int end) {
87+
Set<Character> set = new HashSet<>();
88+
89+
for (int i = start; i <= end; i++) {
90+
Character ch = subStr.charAt(i);
91+
92+
if (set.contains(ch)) {
93+
return true;
94+
}
95+
96+
set.add(ch);
97+
}
98+
99+
return false;
100+
}
101+
}

doc/Leetcode25/leetcode-25.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
2+
# 原题:
3+
4+
【Longest Substring Without Repeating Characters】给定一个字符串,找到最长的没有重复字符的子串.
5+
6+
###### 示例:
7+
###### 给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是 3。
8+
###### 给定 "bbbbb" ,最长的子串就是 "b" ,长度是 1。
9+
###### 给定 "pwwkew" ,最长子串是 "wke" ,长度是 3。
10+
-------------------------
11+
### 方案一:暴力法
12+
穷举所有子字符串,找到不含重复字符的最长子串。
13+
14+
即:执行n趟探测,每趟探测找到以i(0<=i<n)处字符为起始字符的最长无重复字符的子串
15+
16+
#### 画图:
17+
18+
![](../../res/Leetcode25/1.png)
19+
20+
代码:
21+
22+
```java
23+
@Nullable
24+
public String longestSubString(@Nullable String s) {
25+
if (s == null || s.length() == 0) {
26+
return null;
27+
}
28+
29+
int maxLength = 0;
30+
int resultIndex = 0;
31+
32+
int n = s.length();
33+
34+
for (int i = 0; i < n; i++) {
35+
for (int j = i; j < n; j++) {
36+
if (hasDuplicateChar(s, i, j)) {
37+
break;
38+
}
39+
40+
int newLength = j - i + 1;
41+
if (newLength <= maxLength) {
42+
continue;
43+
}
44+
45+
46+
maxLength = newLength;
47+
resultIndex = i;
48+
}
49+
}
50+
51+
return maxLength == 0 ? null : s.substring(resultIndex, resultIndex + maxLength);
52+
}
53+
54+
private boolean hasDuplicateChar(String subStr, int start, int end) {
55+
Set<Character> set = new HashSet<>();
56+
57+
for (int i = start; i <= end; i++) {
58+
Character ch = subStr.charAt(i);
59+
60+
if (set.contains(ch)) {
61+
return true;
62+
}
63+
64+
set.add(ch);
65+
}
66+
67+
return false;
68+
}
69+
70+
```
71+
#### 复杂度
72+
时间复杂度:O(n<sup>3</sup>)
73+
74+
空间复杂度:O(min(n,m)),我们需要 O(k) 的空间来检查子字符串中是否有重复字符,其中 k 表示 Set 的大小。而 Set 的大小取决于字符串 n 的大小以及字符集/字母 m 的大小。
75+
76+
### 方案二:滑动窗口
77+
#### 概述
78+
在暴力法中,我们会反复检查一个子字符串是否含有有重复的字符,但这是没有必要的。如果从索引 i 到 j-1 之间的子字符串 s<sub>ij</sub> 已经被检查为没有重复字符。我们只需要检查 s\[j\] 对应的字符是否已经存在于子字符串 s<sub>ij</sub> 中。
79+
80+
要检查一个字符是否已经在子字符串中,我们可以检查整个子字符串,这将产生一个复杂度为 O(n<sup>2</sup>) 的算法,但我们可以做得更好。
81+
82+
通过使用 HashSet 作为滑动窗口,我们可以用 O(1) 的时间来完成对字符是否在当前的子字符串中的检查。
83+
84+
#### 画图:
85+
![](../../res/Leetcode25/2.png)
86+
#### 代码:
87+
88+
```java
89+
@Nullable
90+
public String longestSubStringSlidingWindow(@Nullable String s) {
91+
if (s == null || s.length() == 0) {
92+
return null;
93+
}
94+
95+
int maxLength = 0;
96+
int resultIndex = 0;
97+
98+
Set<Character> set = new LinkedHashSet<>();
99+
100+
int length = s.length();
101+
int i = 0, j = 0;
102+
103+
while (i < length && j < length) {
104+
105+
if (set.contains(s.charAt(j))) {
106+
set.remove(s.charAt(i));
107+
108+
i++;
109+
continue;
110+
}
111+
112+
set.add(s.charAt(j));
113+
114+
int newLength = j - i + 1;
115+
if (newLength > maxLength) {
116+
maxLength = newLength;
117+
resultIndex = i;
118+
}
119+
120+
j++;
121+
}
122+
123+
return maxLength == 0 ? null : s.substring(resultIndex, resultIndex + maxLength);
124+
}
125+
```
126+
127+
128+
#### 复杂度
129+
这两种方法的时间复杂度和空间复杂度:
130+
时间复杂度:O(n)
131+
132+
空间复杂度:O(min(m,n)),与之前的方法相同。滑动窗口法需要 O(k) 的空间,其中 k 表示 Set 的大小。而 Set 的大小取决于字符串 n 的大小以及字符集/字母 m 的大小。

res/Leetcode25/1.png

442 KB
Loading

res/Leetcode25/2.png

138 KB
Loading

0 commit comments

Comments
 (0)