无重复字符的最长子串-算法

题目

给定一个字符串,给出其中无重复字符的最长子串长度

解题

记录每个字符的下标最大值,再往后遍历的过程中判断是否已有该字符记录,如果有表示有重复,则在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;
}