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

172 阅读2分钟

无重复字符的最长子串

Category Difficulty Likes Dislikes
algorithms Medium (30.73%) 2250 -
Tags

hash-table | two-pointers | string | sliding-window

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

示例 1:

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

示例 2:

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

示例 3:

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

1窗口

这里使用两个指针

用两个指针表示一个范围

指针不断在移动

范围就会在变化

我们称这个过程为移动窗口

说到无重复,我们就会立马使用Set

我们窗口的范围就是

[right,left]

我们把窗口的元素都添加到Set里面

如果在移动left的过程,即添加新的元素时

发现该元素在Set中出现

我们就要让移动right到该元素后

这样就使得窗口内的元素不会重复

/*
 * @lc app=leetcode.cn id=3 lang=javascript
 *
 * [3] 无重复字符的最长子串
 */
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function (s) {
	let [max, left, right] = [0, 0, 0]
	const set = new Set()
	while (right < s.length) {
		if (!set.has(s[right])) {
			set.add(s[right++])
			max = Math.max(max, right - left)
		} else {
			set.delete(s[left++])
		}
	}
	return max
};

2窗口优化

这里我们的left是一步一步移动

直到删除了重复元素

即遇到了s[left] === s[right] 注:left !== right

此时删除了set.delete(s[left++])

那么现在set里的元素范围就是[left,right]

因为set.has(s[right])此时就不存在了,即false

所以就会走 if(!set.has(s[right]))

上面这里的left是一步一步才走到

s[left] === s[right]的位置的

那么

如果遇到重复的了

我们取出重复元素的下标直接赋给left即可

而不是上面的left一步一步的移动

直到s[left] === s[right]

然后把从(left,right]开始

我们这里需要找到是

  • s[left] === s[right]
  • left

那么我们如果使用map

存储的是

<index,value>

我们在[left,right)以后的时候

s[right]在该范围内发现有重复的

我们假装这个值是s[right_2]

我们只要使得left = right_2 + 1

使得那范围[right_2 + 1,right]

<值,下标>

var lengthOfLongestSubstring = function (s) {
	let [max, left, right] = [0, 0, 0]
	let map = new Map()
	while (right < s.length) {
		if (map.has(s[right]))
			left = Math.max(map.get(s[right]) + 1, left)
		map.set(s[right], right++)
		max = Math.max(max, right - left)
	}
	return max
};