3.Longest Substring Without Repeating Characters
原题
Given a string, find the length of the longest substring without 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.
解决
题目的要求是取最长的不重复子串。一看到是不间断的,就可以想到使用滑动窗口来做。也很明显,这题也可以直接使用暴力解法,枚举后求出最长的不重复子串。
方法1:暴力
public static int lengthOfLongestSubstring(String s) {
//这个暴力解法也还是有很多值得优化的地方O(n^2)
if(s == null || s.length() <= 0 )
return 0;
if (s.length() == 1)
return 1;
int maxLen = 0;
//最外层遍历字符的长度
for(int i = 0; i < s.length() - 1; i++) {
//第二层遍历不重复的最右端
Set<Character> set = new HashSet();
set.add(s.charAt(i));
for(int j = i + 1; j < s.length(); j ++) {
//子串中是否有重复
char c = s.charAt(j);
if(!set.contains(c))
set.add(s.charAt(j));
else {
break;
}
}
maxLen = maxLen > set.size() ? maxLen : set.size();
}
return maxLen;
}
方法2:普通滑动窗口法
public static int lengthOfLongestSubstring(String s) {
//方法2: 使用普通滑动窗口。具体思路:
//一个可变的数组存储不重复的数值。
//R向右边滑动的同时,判断是不是到最右侧。
//每次向右滑动后,判断是否新进入的与之前的有重复,如果重复的话,最左侧--,直到没有重复。
//每次有不重复的子串时,更新全局最大值
if(s == null || s.length() == 0 )
return 0;
int L = 0, R = 0, n = s.length();
Set<Character> window = new HashSet<>();
//因为s肯定不为空,所以maxLen至少也有1
int maxLen = 1;
//保证右侧不越界
while(L < n && R < n) {
if(!window.contains(s.charAt(R))) {
window.add(s.charAt(R ++));
maxLen = maxLen > (R - L) ? maxLen : R - L;
}
else {
window.remove(s.charAt(L ++));
}
}
return maxLen;
}
方法3:优化滑动窗口法
很明显,方法2的普通滑动窗口法是可以优化的,左侧不必每次都减减,而可以直接把窗口内重复的值及其左侧都舍弃掉。
public static int lengthOfLongestSubstring(String s) {
//方法3: 使用优化滑动窗口。具体思路:
//map的key存储不重复的值,value存储位置
//R向右边滑动的同时,判断是不是到最右侧。
//每次向右滑动后,判断是否新进入的与之前的有重复,如果重复的话,最左侧--,直到没有重复。
//每次有不重复的子串时,更新全局最大值
if(s == null || s.length() == 0 )
return 0;
int L = 0, R = 0, n = s.length();
Map<Character, Integer> window = new HashMap<>();
//因为s肯定不为空,所以maxLen至少也有1
int maxLen = 1;
//保证右侧不越界
while(L < n && R < n) {
//当发现重复的字符时,将字符的索引与窗口的左边进行对比,将窗口的左边直接跳到该重复字符的索引处
if (window.containsKey(s.charAt(R))) {
L = window.get(s.charAt(R)) > L ? window.get(s.charAt(R)) : L;
}
maxLen = maxLen > R - L + 1 ? maxLen : R - L + 1;
window.put(s.charAt(R), ++ R);
}
return maxLen;
}