同向双指针——滑动窗口
讲解实例:LeetCode209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
- 暴力双循环 时间复杂度O(n^2).
- 同向双指针
就举示例1的例子,设置左右指针初试都为0,想要找>=7的最短子数组,可以遍历每个右端点,找到以每个数为右端点的最短数组。
在右指针向右遍历的过程中,若数组小于target=7则右指针继续向右移动
我们假设现在取到了2 3 1 2即2为右端点,这是大于等于7的,那么为了取到最短的数组,我们可以将左指针向右移动,这些就可以缩短数组,直到数组<7即取到3 1 2的情况,这时我们已经知道了以2为右端点的数组>=7最短为2 3 1 2 ,长度为4
之后我们继续遍历右指针,向右移动,此时左端点为3 ,且此时我们的左指针不需要回退,因为我们已知 2 3 1 2>7,若左指针回退,而右指针却向右移动,则必然不是最短的子数组,故此时我们的数组为3 1 2 4>7,故向之前一样,左指针向右移动,直到数组<7即取到2 4的情况,这时我们已经知道了以4为右端点的数组>=7最短为1 2 4 ,长度为3
右指针继续向右,此时3为数组右端点,2为左端点, 此时我们判断数组2 4 3>7,那么我们和之前一样,向右移动左指针,直到<7,此时我们知道以3为右端点的数组最短为4 3。
这就是同向双指针的具体流程,右指针与左指针的移动距离都最多为n,故时间复杂度为O(n).
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n = len(nums)
ans = n + 1 # 也可以写 inf
s = left = 0
for right, x in enumerate(nums):
s += x
# while s - nums[left] >= target:
# s -= nums[left]
# left += 1
# if s >= target:
# ans = min(ans, right-left+1)
while s >= target: # 满足要求
ans = min(ans, right - left + 1)
s -= nums[left]
left += 1
return ans if ans <= n else 0
练习LeetCode713. 乘积小于 K 的子数组
给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于 k 的连续子数组的数目。
与上一题一样,遍历右端点,乘积>=k时左端点右移
而需要注意的是子数组数目,假设此时数组为5 2 6,此次<k,那么以6为右端点的<k的子数组为[5,2,6],[2,6],[6]
故总结若以 right 为端点,则left向右移到<k后,所有的[left —right],[left+1 —right]·····[right-1,right],[rigth]都满足条件,即为right-left+1
func numSubarrayProductLessThanK(nums []int, k int) (ans int) {
if k <= 1 {
return
}
prod, left := 1, 0
for right, x := range nums {
prod *= x
for prod >= k { // 不满足要求
prod /= nums[left]
left++
}
ans += right - left + 1
}
return ans
}
练习LeetCode3. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
func lengthOfLongestSubstring(s string) (ans int) {
l := 0
cnt:=[128]int{}
for r,c:=range s{
cnt[c]++
for cnt[c]>1{
cnt[s[l]]--
l++
}
ans = max(ans,r-l+1)
}
return ans
}
func max(a, b int) int { if b > a { return b }; return a }
练习LeetCode1004. 最大连续 1 的个数
给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。
func longestOnes(nums []int, k int) int {
l,ans,cnt:=0,0,0
for r,num:=range nums{
if num==0{
cnt++
}
for cnt>k{
if nums[l]==0{
cnt--
}
l++
}
ans=max(ans,r-l+1)
}
return ans
}
func max(a, b int) int { if a < b { return b }; return a }