Skip to content

3. 无重复字符的最长子串

3. 无重复字符的最长子串

解法一: 线性法

  • 快慢指针线性扫描
  • i 是慢指针,j 是快指针
  • 当 j 遇到一个重复出现的字符时,该字符在 i, j 之间的 found 位置
  • 慢指针 i,跳到 found + 1 处,继续扫描
class Solution {
  public:
  int lengthOfLongestSubstring(string s) {
    int len = s.length();
    if (len <= 1) return len;

    int i = 0, j = 1, maxLen = 1, curLen = 1, found = -1;

    while (j < s.len)) {
      found = s.substr(i, curLen).find(s[j]);
      if (found < 0 ) {
        j++;
        curLen++;
        maxLen = curLen > maxLen ? curLen : maxLen;
      } else {
        i += found + 1;
        curLen -= found + 1;
      }
    }

    return maxLen;
  }
};

解法二: 利用 Set 判重

  • 定义集合 set;
  • 从给定字符串的头开始,每次检查当前字符是否在集合内;
  • 如果不在,说明该字符不会造成重复和冲突,加入集合,并统计集合长度,或为最长子串;
  • 定义快慢指针:i 是慢指针,j 是快指针;
  • 当 j 遇到一个重复出现的字符时,从慢指针开始一个一个将 i 指针指向的字符从集合里删除
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  const len = s.length
  if (len <= 1) {
    return len;
  }

  let max = 1;
  let i = 0, j = 0; //  快慢指针
  let set = new Set();

  while(j < len) {
    while (set.has(s[j])) {
      set.delete(s[i++]);
    }

    set.add(s[j++]);
    max = max < set.size ? set.size : max;
  }

  return max;
};
  • 快指针添加到 set,慢指针从 set 删除,每次操作set 时间复杂度 O(1)
  • 时间复杂度:字符串最多遍历两遍 n * O(1) + n * O(1) = O(n)
  • 空间复杂度:O(n)

解法三: HashMap 优化

  • 利用 hash 表记录下标
  • 每次遇到重复字符,下标记为 found,慢指针移动到 found + 1
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  let len = s.length;
  if (len <= 1) {
    return len;
  }

  let max = 0;
  let i = 0, j = 0;
  let map = {}; // 记录下标

  while (j < len) {
    let found = map[s[j]];
    if (found !== undefined && found >= i) {
      i = found + 1;
    }

    map[s[j]] = j;
    j++;
    max = max < j - i ? j - i : max;
  }

  return max;
}