一、问题描述
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb"
, the answer is "abc"
, which the length is 3.
Given "bbbbb"
, the answer is "b"
, with the length of 1.
Given "pwwkew"
, 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.
二、我的解法
时间O(n^2)的解法,i有n个开始点,j有n个可能的结束点。每次只判断s[j]是否在当前的substring里。 (是n2还是n3?)
用hashSet帮助判断当前要加入的char是否已经存在在substring里。
class Solution {
public int lengthOfLongestSubstring(String s) {
char[] char_arr = s.toCharArray();
int max_len = 0;
int cur_len;
Set<Character> appeared = new HashSet<Character>();
for(int i = 0; i < char_arr.length; i ++){
int j = i;
appeared.clear();
cur_len = 0;
while(j < char_arr.length && appeared.add(char_arr[j])){
cur_len ++;
j ++;
}
if(cur_len > max_len){
max_len = cur_len;
}
}
return max_len;
}
}
三、淫奇技巧
https://leetcode.com/articles/longest-substring-without-repeating-characters/
1. O(2n)解法
滑动窗口。从左往右扫描,当遇到重复字母时,以上一个重复字母的index +1,作为新的搜索起始位置。因为设s[j]是substring[i, j)的重复元素。如果再从包含s[j]的字串i+1重新搜索已经没有必要了,因为该字串结果必定小于[i, j)。所以直接从重复字母的index +1,作为新的搜索起始位置。
当要加入的s[j]重复了,就从hashset里依次删除元素,直到把重复的那个元素删除为止,再把s[j]加入。
-
Time complexity : O(2n)=O(n). 最坏情况是每个元素被i和j各遍历一遍。
-
Space complexity : O(min(m,n)). 和我的解法一样。m是input string里不同char的数量,n是string长度。
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;
}
}
2. O(n解法)
思路和上面解法一样,但是怎样从index+1开始搜索更胜一筹。存储用了hashmap,有char到index的映射信息。
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;
}
}
四、反思&收获
1. hashset是好东西
2. 多存有用的信息可以减少复杂度;
3. 算复杂度要继续加强
4. 搜索字符串策略的优化要加强~