SlideWindow
Last updated
Last updated
//window version, better
//window version, better
var lengthOfLongestSubstring = function (s) {
const slideWindow = {},
len = s.length
let l = 0,
r = 0,
ret = 0
while (r < len) {
const rChar = s[r++]
slideWindow[rChar] ? slideWindow[rChar]++ : (slideWindow[rChar] = 1)
//left一直缩到window里当前rChar不重复的位置
while (slideWindow[rChar] > 1) slideWindow[s[l++]]--
ret = Math.max(ret, r - l)
}
return ret
}
var lengthOfLongestSubstring = function (s) {
const len = s.length,
map = new Map()
let l = 0,
r = 0,
ret = 0
while (r < len) {
const rChar = s[r]
//update left
if (map.has(rChar)) l = Math.max(l, map.get(rChar) + 1)
ret = Math.max(ret, r - l + 1)
map.set(rChar, r++)
}
return ret
}var minWindow = function (s, t) {
let sLen = s.length,
tLen = t.length
if (sLen === 0 || tLen === 0 || sLen < tLen) return ''
let slideWindow = {},
need = {},
begin = 0,
l = 0,
r = 0,
minLen = Infinity,
//窗口中满足need条件的字符个数,如果valid和need.size的大小相同,则说明窗口已满足条件,已完全覆盖了串t
valid = 0
for (let c of t) need[c] ? need[c]++ : (need[c] = 1)
while (r < sLen) {
const rChar = s[r++]
//过滤需要的字符
if (need[rChar]) {
slideWindow[rChar] ? slideWindow[rChar]++ : (slideWindow[rChar] = 1)
if (slideWindow[rChar] === need[rChar]) valid++
}
//t中所有字符已全覆盖,判断是否收缩
while (valid === Object.keys(need).length) {
if (r - l < minLen) {
minLen = r - l
begin = l
}
//更新左边界
const lChar = s[l++]
//过滤需要的字符,行为同上面加的时候
if (need[lChar]) {
if (slideWindow[lChar] === need[lChar]) valid--
slideWindow[lChar]--
}
}
}
return minLen === Infinity ? '' : s.substring(begin, begin + minLen)
}// 1 brute force O(n^2) - O(1)
var minSubArrayLen = function (s, nums) {
if (nums.length === 0) return 0
let len = nums.length,
ret = Infinity
for (let i = 0; i < len; i++) {
let sum = 0
for (let j = i; j < len; j++) {
sum += nums[j]
if (sum >= s) {
ret = Math.min(ret, j - i + 1)
//找最短,找到即返回
break
}
}
}
return ret === Infinity ? 0 : ret
}
// 2 前缀和 + 二分查找
// 3 双指针滑动窗口 O(n) - O(1)
var minSubArrayLen = function (s, nums) {
const len = nums.length
if (len === 0) return 0
let ret = Infinity,
l = 0, //表示滑动窗口的起始位置
r = 0, //表示滑动窗口的结束位置
sum = 0
while (r < len) {
sum += nums[r++]
while (sum >= s) {
ret = Math.min(ret, r - l)
sum -= nums[l++]
}
}
return ret === Infinity ? 0 : ret
}//brute force O(n * k) - O(k)
var maxSlidingWindow = function (nums, k) {
let slideWindow = []
const ret = [],
len = nums.length
//能形成的最大窗口个数
for (let i = 0; i < len - k + 1; i++) {
for (let j = 0; j < k; j++) slideWindow.push(nums[i + j])
ret.push(Math.max(...slideWindow))
slideWindow.length = 0
}
return ret
}
//deque O(n) - O(n)
//头尾尾头
var maxSlidingWindow = function (nums, k) {
//放的下标,递减队列,第一个第一大的index,依此类推
let deque = [],
ret = []
for (let i = 0, len = nums.length; i < len; i++) {
//队列满了移出去一个
//L,R 来标记窗口的左边界和右边界,当窗口大小形成时,L 和 R 一起向右移,每次移动时,判断队首的值的数组下标是否在 [L,R] 中,如果不在则需要弹出队首的值
if (deque.length && deque[0] < i - k + 1) deque.shift()
//维护递减队列
while (deque.length && nums[deque[deque.length - 1]] < nums[i]) deque.pop()
deque.push(i)
//开始检查结果
if (i >= k - 1) ret.push(nums[deque[0]])
}
return ret
}
//stack O(n) - O(n)
var maxSlidingWindow = function (nums, k) {
let l = 0,
r = -1
//单调递减栈,存的是下标
const stack = [],
ans = []
for (let i = 0, len = nums.length; i < len; i++) {
if (stack.length && i - k + 1 > stack[l]) l++
//缩小右边界直到满足条件
while (stack.length && l <= r && nums[stack[r]] < nums[i]) r--
stack[++r] = i
//满足条件才放答案
if (i >= k - 1) ans.push(nums[stack[l]])
}
return ans
}var findAnagrams = function (s, p) {
let sLen = s.length,
pLen = p.length
if (sLen === 0 || pLen === 0 || pLen > sLen) return []
let left = 0,
right = 0,
valid = 0,
need = {},
slideWindow = {},
ret = []
for (let c of p) need[c] ? need[c]++ : (need[c] = 1)
while (right < sLen) {
let rightChar = s[right++]
if (need[rightChar]) {
slideWindow[rightChar]
? slideWindow[rightChar]++
: (slideWindow[rightChar] = 1)
if (slideWindow[rightChar] === need[rightChar]) valid++
}
while (right - left >= pLen) {
if (valid === Object.keys(need).length) ret.push(left)
let leftChar = s[left++]
if (need[leftChar]) {
if (slideWindow[leftChar] === need[leftChar]) valid--
slideWindow[leftChar]--
}
}
}
return ret
}var checkInclusion = function (s, t) {
let sLen = s.length,
tLen = t.length
if (sLen === 0 || sLen > tLen) return false
let slideWindow = {},
need = {},
l = 0,
r = 0,
//表示窗口中满足 need 条件的字符个数,如果 valid 和 need.size 的大小相同,则说明窗口已满足条件,已经完全覆盖了串t
valid = 0
for (let c of s) need[c] ? need[c]++ : (need[c] = 1)
while (r < tLen) {
const rChar = t[r++]
//过滤需要的字符
if (need[rChar]) {
slideWindow[rChar] ? slideWindow[rChar]++ : (slideWindow[rChar] = 1)
if (slideWindow[rChar] === need[rChar]) valid++
}
//长度够则判断
if (r - l >= sLen) {
if (valid === Object.keys(need).length) return true
//更新左边界
const lChar = t[l++]
//过滤需要的字符
if (need[lChar]) {
if (slideWindow[lChar] === need[lChar]) valid--
slideWindow[lChar]--
}
}
}
return false
}