leetcode充电站 _ 无重复字符的最长子串

47 阅读3分钟

1、题目描述

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例1:

输入:“abcabcbb”
输出:3
解释:因为无重复字符的最长子串是“abc”,所以其长度为`3`

示例 2:

输入:“bbbbb”
输出:1
解释:因为无重复字符的最长子串是“b”,所以其长度为`1`

示例 3:

输入:“pwwkew”
输出:3
解释:因为无重复字符的最长子串是“wke”,所以其长度为`3`。
请注意,你的答案必须是 子串 的长度,“pwke”是一个子序列,不是子串。

2、解题思路

这个题目可以使用双指针+map来实现:

  • 首先用双指针维护一个滑动窗口用来剪切子串。
  • 开始时,两个指针都在起始位置,不断移动右指针,遇到重复的字符,就将左指针向后移动一位。
  • 右指针每次移动,都计算出两个指针之间的字符个数,并返回最大值。
  • 每次右指针移动还需要将右指针的索引和值存在Map中,便于后面遇到重复值时让左指针进行移动。

需要注意的是,在左指针移动之后,map中还存在其之前的值,所以还要限制map中已经存在的值的索引要大于左指针的索引,也就是必须处于两指针之间的滑动窗口。

该算法的时间复杂度为O(n),空间复杂度为O(m),其中m是最长子串的长度。

3、代码实现

/**
 * 
 */
var lengthOfLongestSubstring = function(s) {
	let res = 0
	let map = {}
    
    for(let left = 0, right = 0; right < s.length; right++) {
      const char = s[right]
      if (map[char] >= 0 && map[char] >= left) {
      	left = map[char] + 1
      }
      res = Math.max(res, right - left + 1)
      map[char] = right
    }
    return res
};

滑动窗口 - > “无重复字符的最长子串”

思路:

1、滑动窗口:维护一个窗口[left, right], 表示当前考察的子串。

2、哈希记录:用对象map记录每个字符最后出现的位置。

3、窗口调整:遇到重复字符时,移动左边界到重复字符的下一个位置。

代码逐行解析:

var lengthOfLongestSubstring = function(s) {
	let res = 0; // 存储最长子串
	let map = {}; // 记录字符最后出现位置的哈希表

    // 滑动窗口:left是窗口左边界,right是右边界
	for (let left = 0; right = 0; right < s.length; right++) {
      const char = s[right]; // 当前右边界字符

 	  // 如果字符已存在且在当前窗口内(map[char] >= left)
      if (map[char] >= 0 && map[char] >= left) {
        left = map[char] + 1; // 移动左边界到重复字符的下一个位置
      }

      // 更新最大长度(当前窗口大小:right-left+1)
      res = Math.max(res, right - left + 1);

      // 记录/更新当前字符的位置
      map[char] = right;
	}
	return res; // 返回找到的最大长度 
};

示例分析:

输入“abcabcbb”的执行过程:

1、right = 0 (a): map = {a: 0}, res = 1

2、right = 1 (b): map = {a: 0, b: 1}, res = 2

3、right = 2 (c): map = {a: 0, b: 1, c: 2}, res = 3

4、right = 3 (a): 发现重复, left=1 -> res保持3

5、right = 4 (b): 发现重复, left=2 -> res保持3

6、right = 5 (c): 发现重复, left=3 -> res保持3

7、right = 6 (c): 发现重复, left=5 -> res=3

8、right = 7 (b): 发现重复, left=7 -> res=3

最终返回3("abc")

复杂度分析:

  • 时间复杂度:O(n),只需遍历一次字符串。

  • 空间复杂度:O(min(m, n)), m是字符集大小