基础算法一:同向双指针

Posted Pistachiout

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基础算法一:同向双指针相关的知识,希望对你有一定的参考价值。

同向双指针——滑动窗口

讲解实例:LeetCode209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

  1. 暴力双循环 时间复杂度O(n^2).
  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 的最大个数 。

最多翻转 k 个 0,即数组中最多允许有k个0

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 

练习LeetCode1234. 替换子串得到平衡字符串

有一个只含有 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符,且长度为 n 的字符串。假如在该字符串中,这四个字符都恰好出现 n/4 次,那么它就是一个「平衡字符串」。给你一个这样的字符串 s,请通过「替换一个子串」的方式,使原字符串 s 变成一个「平衡字符串」。你可以用和「待替换子串」长度相同的 任何 其他字符串来完成替换。请返回待替换子串的最小可能长度。如果原字符串自身就是一个平衡字符串,则返回 0。

func balancedString(s string) int 
    left,m:=0,len(s)/4
    cnt:=[100]int
    ans:=1000001
    for _,c:=range s
        cnt[c]++
    
    if cnt['Q'] == m && cnt['W'] == m && cnt['E'] == m && cnt['R'] == m 
        return 0 // 已经符合要求啦
    
    for right,c:=range s
        cnt[c]--
        for cnt['Q'] <= m && cnt['W'] <= m && cnt['E'] <= m && cnt['R'] <= m//满足条件
            ans=min(ans,right-left+1)
            cnt[s[left]]++
            left++
        
    
    return ans

func min(a,b int)intif a>b return b return a

总结:

求最小值时,一般是遍历数组由满足条件到不满足条件,右指针每次遍历时取左指针最后一次满足条件的最小结果,即在左指针循环内部

求最大值时,一般是遍历数组由不满足条件到满足条件,右指针每次遍历时取左指针第一次满足条件的最大结果,即在左指针循环退出后

以上是关于基础算法一:同向双指针的主要内容,如果未能解决你的问题,请参考以下文章

算法专题(02)双指针(01) 简单LeetCode 977

算法入门 03双指针(简单 - 第二题)LeetCode 283

leetcode 524. 通过删除字母匹配到字典里最长单词双指针,在不同字符串中同向查找

leetcode 524. 通过删除字母匹配到字典里最长单词双指针,在不同字符串中同向查找

leetcode 524. 通过删除字母匹配到字典里最长单词双指针在不同字符串中同向查找

leetcode 524. 通过删除字母匹配到字典里最长单词双指针,在不同字符串中同向查找