文章目录
更多LeetCode题解
MySolution
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int res = 0;
for (int i = 0; i < s.size(); i++) {
vector<char> v;
for (int j = i; j < s.size(); j++) {
if (find(v.begin(), v.end(), s[j]) != v.end()) break;
v.push_back(s[j]);
if (v.size() +1 > res) res = v.size();
}
}
return res;
}
};
注意点
第一次提交挂了:
- 没有考虑空字符的情况,直接将res置1了,这样的话j初始不能初始化为i+1,否则无法正确处理单个字符的情况。
java
- 看了官方解答发现我的解法就是Approach 1: Brute Force暴力法,那就看看官方的java代码吧
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int ans = 0;
for (int i = 0; i < n; i++)
for (int j = i + 1; j <= n; j++)
if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
return ans;
}
public boolean allUnique(String s, int start, int end) {
Set<Character> set = new HashSet<>();
for (int i = start; i < end; i++) {
Character ch = s.charAt(i);
if (set.contains(ch)) return false;
set.add(ch);
}
return true;
}
}
Approach 2: Sliding Window
java
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
// try to extend the range [i, j]
if (!set.contains(s.charAt(j))){
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);
}
else {
set.remove(s.charAt(i++));
}
}
return ans;
}
}
C++
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int i = 0, j = 0;
int res = 0;
unordered_set<char> existed;
while (j < s.size()) {
if (!existed.count(s[j])) {
existed.insert(s[j++]);
res = max(res, j - i);
}
else {
existed.erase(s[i++]);
}
}
return res;
}
};
思想
方法的精髓就在于左游标i
与右游标j
,右游标不断右移,并将指向的字符不断存入任意的容器,一旦发现容器中已经存在的字符,则将容器中此字符删除,并将左游标右移一位。
为什么滑窗的复杂度就低下来了呢?
In the naive approaches, we repeatedly check a substring to see if it has duplicate character. But it is unnecessary. If a substring s i j s_{ij} sij from index i i i to j − 1 j-1 j−1 is already checked to have no duplicate characters. We only need to check if s [ j ] s[j] s[j] is already in the substring s i j s_{ij} sij.To check if a character is already in the substring, we can scan the substring, which leads to an O ( n 2 ) O(n^2) O(n2) algorithm. But we can do better.By using HashSet as a sliding window, checking if a character in the current can be done in O ( 1 ) O(1) O(1).
Approach 3: Sliding Window Optimized
java
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>(); // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
}
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1);
}
return ans;
}
}
C++
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int res = 0;
unordered_map<char, int> existed;
for (int i = 0, j = 0; j < s.size(); j++) {
if (existed.find(s[j]) != existed.end()) {
i = max(i, existed[s[j]]);
}
existed.insert_or_assign(s[j], j + 1);//C++17 at least
res = max(res, j - i + 1);
}
return res;
}
};
思想
使用一个hashmap存放每个字符的下一个字符的下标,一旦遇到已经出现过的字符,则更新左游标为hashmap中存放的值(即上一个此字符的下一字符位置),且更新hashmap中此字符的值。
假设是ASCII字符集
此方法与hashmap法完全一样,只不过通过空间换取时间,新建一个含有128个元素的数组,128即ASCII字符集的字符数。用数组存放上一种方法中用hashmap存放的值。
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
int[] index = new int[128]; // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
i = Math.max(index[s.charAt(j)], i);
ans = Math.max(ans, j - i + 1);
index[s.charAt(j)] = j + 1;
}
return ans;
}
}
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int res = 0;
int existed[128] = { 0 };
for (int i = 0, j = 0; j < s.size(); j++) {
if (existed[s[j]]) i = max(i, existed[s[j]]);
existed[s[j]] = j + 1;
res = max(res, j - i + 1);
}
return res;
}
};