题目
给定一个字符串,给出其中无重复字符的最长子串长度
解题
记录每个字符的下标最大值,再往后遍历的过程中判断是否已有该字符记录,如果有表示有重复,则在i到j中间为可能最长子串。如果排除子串的问题呢?通过双指针,一个快,一个慢,快指针循环往后遍历,慢指针根据是否与慢指针相同字符的位置做位移。因此可以排除掉子串的问题
比如i=5,j=10的位置都是a,但其中有i1=7,j2=8的位置都是b,那么5~10必然不能取。那么在快指针向后移动经过8位置时,判断7位置是重复字符,则将慢指针更新到8位置,就不会有上面的那种情况。
//利用动态规划的思想
public int findMaxSubStringWithoutDuplicateChar(String source){
int start = 0;
int end = 0;
int res = 0;
Map<Character, Integer> charMaxIndexMap = new HashMap<>();
while (end < source.length()) {
char endChar = source.charAt(end);
if (charMaxIndexMap.containsKey(endChar)) {
start = Math.max(start, charMaxIndexMap.get(endChar) + 1);
res = Math.max(res, end - start + 1);
} else {
res = Math.max(res, end - start + 1);
}
charMaxIndexMap.put(endChar, end);
end++;
}
return res;
}
//滑动窗口
public static int getLongestSubStringWithWindow(String source) {
if(source==null||source.length()==0){
return 0;
}
Set<Character> window = new HashSet<>();
int slow = 0;
int fast = 1;
int result = 1;
int length = source.length();
window.add(source.charAt(slow));
while (fast < length) {
if (window.add(source.charAt(fast))) {
fast++;
} else {
while (source.charAt(slow) != source.charAt(fast)) {
window.remove(source.charAt(slow));
slow++;
}
window.remove(source.charAt(slow));
slow++;
}
result = Math.max(result, fast - slow);
}
return result;
}
//地图记录模式,逐步更新已走过的字符,然后用于当前最右字符
public static int getLongestSubStringOfWalked(String source) {
int length = source.length();
int left = 0;
int right = 0;
int result = 0;
boolean[] walkedRecord = new boolean[256];
while (right < length) {
int curChar = (int)source.charAt(right);
while (left < right && walkedRecord[curChar]) {
walkedRecord[(int)source.charAt(left++)] = false;
}
walkedRecord[curChar] = true;
result = Math.max(result, right - left + 1);
right++;
}
return result;
}