Given a string, find the length of the longest substringwithout repeating characters.
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc"
, with the length of 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b"
, with the length of 1.
Example 3:
Input: "pwwkew" Output: 3 Explanation: The answer is"wke"
, with the length of 3. Note that the answer must be a substring,"pwke"
is a subsequence and not a substring.
我的思路:
所有与数组相关题目的最好情况肯定是线性扫描, 而且我还需要维护一个中间结果,也就是一个子串,那我需要双指针, left和right.
那如果我想知道,下一个新的character是不是在之前的substring出现过,那我就要将之前的substring的内容存起来。
那怎么存?
Array, Set, Dict.
Array肯定不行,那就会变成o(n*n).
Set的话,肯定不如Dict更优秀. 如果遇到 abcdefgc的情况, 当最后一个c出现之后,我想要从第一个c之后的d开始,所以我需要记录substring的index. 那就用Dict. key是character, value是index.
于是我写好了代码
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) return 0;
Map<Character, Integer> map = new HashMap<>();
int left = 0, right = 0;
int res = 0;
while(right < s.length()){
if (!map.containsKey(s.charAt(right))){
map.put(s.charAt(right), right);
right ++;
res = Math.max(res, right - left);
}
else {
left = map.get(s.charAt(right)) + 1;
map.put(s.charAt(right), right);
right++;
}
}
return res;
}
我的test case少覆盖了一种情况: 那就是 tmmzuxt.
也就是说当我的双指针 left 和 right, right遇到了之前map里面存在的character, left直接移动到了和right一样的字母的下一个位置. 但是我忘记在map里面同样要删掉之前出现过的字母了。也就是说,当我遇到了第二个m的时候,我直接把left 设置成了第二个m的位置。但是此时,t依然在我的字典里,可是t不应该是我考虑的范畴。
solution: 1. 在字典里删掉index比m小的字母。但这就又需要扫整个字典,复杂度又会变回(n*n).
2. 我并没有想起来,应该多思考一下。看了答案。毕竟我这个是字典,字典就是记录了index, 如果它比我想要的index小,那我不考虑不就是了嘛。
更新版的代码 (只在if条件语句里面加了一个判断):
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) return 0;
Map<Character, Integer> map = new HashMap<>();
int left = 0, right = 0;
int res = 0;
while(right < s.length()){
if (!map.containsKey(s.charAt(right)) || map.get(s.charAt(right)) < left){
map.put(s.charAt(right), right);
right ++;
res = Math.max(res, right - left);
}
else {
left = map.get(s.charAt(right)) + 1;
map.put(s.charAt(right), right);
right++;
}
}
return res;
}
solution的最优代码:
class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Map<Character, Integer> map = new HashMap<>();
int res = 0;
for(int i = 0, j = 0; j < n; j++) {
if (map.containsKey(s.charAt(j)))
i = Math.max(map.get(s.charAt(j)), i);
res = Math.max(res, j - i + 1);
map.put(s.charAt(j), j + 1);
}
return res;
}
}