LeetCode HOT 100 —— 3. 无重复字符的最长子串

310 阅读1分钟

题目描述

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

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

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

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成

解题思路

暴力解法

生成所有长度不同的字符串,并依次判断最大长度,效率巨低

单哈希表

也是慢的一批,我运行约300多ms

这个思路也能解决,从字符串的第一个字符开始遍历,判断map是否存在当前指向的字符,如果不存在就向map里面添加,如果存在,就判断当前map的长度是否大于max,然后解决当前指向的字符是最后一位,如果是取map内的值+1,清空map,因为这个是使用map的长度来代表最大值。

效率影响最大的就是在做Array.from(map).length操作。

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  let start = 0
  let max = 0
  let map = new Map()
  if(s.length === 1) return 1
  while (start < s.length) {
    if(map.has(s[start])) {
      if(Array.from(map).length > max) {
        max = Array.from(map).length
      }
      if(map.get(s[start]) !== start-1) {
        start = map.get(s[start]) + 1
      }
      map.clear()
    }
    map.set(s[start], start)
    start++
  }
  if(Array.from(map).length > max) return Array.from(map).length
  return max
};

双指针+哈希

效率提高了很多,70-80ms

采用滑动窗口的思路,从第一个字符开始,开始向后遍历,只要map中不存在,继续向后遍历,当map中存在,start取当前start和map中存储对应的值+1后最大值,这里的目的是跳过指向的字符从下一个开始和如果当前指向的值时窗口内的最后一个,也直接指向下一个。用start至end的长度代表max,将他们的长度和max值比较,最大则赋给max

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  let max = 0
  const map = new Map()
  for (let start = 0, end = 0; end < s.length; end++) {
      start = map.has(s[end]) ? Math.max(start, map.get(s[end]) + 1) : start
      map.set(s[end], end)
      max = Math.max(max, end - start + 1)
  }
  return max
};