0
点赞
收藏
分享

微信扫一扫

数组-滑动窗口

程序猿不脱发2 2022-03-30 阅读 67

209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

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

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        sum=0
        n=len(nums)
        res=n+1
        j=0
        #i是右指针 j左指针
        for i in range(0,n):
            sum+=nums[i]
            # 如果sum持续大于target 就不右移扩大窗口 而是左移缩小窗口
            while(sum>=target):
                # 因为满足sum>=target 所以更新当前区间长度
                res=min(res,i-j+1)
                sum-=nums[j]
                j+=1
            #跳出循环 说明sum不满足>=target 所以需要继续移动右指针
            
        # 如果res没有被赋值 则返回0
        if res==n+1:
            return 0
        else:
            return res

904. 水果成篮

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

示例 1:

输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。
示例 2:

输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。
示例 3:

输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。
示例 4:

输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。

思路:freq数组记录现在窗口中两种水果的数目,count记录现在窗口中有多少种不同的水果,如果count<=2,那么right指针可以一直向右移动,直到count>2,当count>2时,说明窗口中的水果种类超过2,为了减少水果种类,left指针就要向右移动,移动的同时还要更新freq数组,最后取最大值即可。

模板

def findSubArray(nums):
    N = len(nums) # 数组/字符串长度
    left, right = 0, 0 # 双指针,表示当前遍历的区间[left, right],闭区间
    sums = 0 # 用于统计 子数组/子区间 是否有效,根据题目可能会改成求和/计数
    res = 0 # 保存最大的满足题目要求的 子数组/子串 长度
    while right < N: # 当右边的指针没有搜索到 数组/字符串 的结尾
        sums += nums[right] # 增加当前右边指针的数字/字符的求和/计数
        while 区间[left, right]不符合题意:# 此时需要一直移动左指针,直至找到一个符合题意的区间
            sums -= nums[left] # 移动左指针前需要从counter中减少left位置字符的求和/计数
            left += 1 # 真正的移动左指针,注意不能跟上面一行代码写反
        # 到 while 结束时,我们找到了一个符合题意要求的 子数组/子串
        res = max(res, right - left + 1) # 需要更新结果
        right += 1 # 移动右指针,去探索新的区间
    return res

作者:fuxuemingzhu
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/fen-xiang-hua-dong-chuang-kou-mo-ban-mia-f76z/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution:
    def totalFruit(self, fruits: List[int]) -> int:
        # 本质上是 最多包含两个不同字符的最长连续字串
        left=0
        n=len(fruits)
        # freq 计算每种类出现的频次 count计算品种数量
        # freq 相当于hash表 长度要是len和max(fruit)的最大值 防止出现[1,2,3,3,46]这种
        freq=[0]*max(max(fruits),n)
        count=0
        res=0
        for right in range(0,n):
            freq[fruits[right]]+=1
            #说明第一次加入该品种 种类加1
            if freq[fruits[right]]==1:
                count += 1
            # 品种种类大于2 移动左指针 缩小窗口
            while(count>2):
                #一直减少左指针指向的品种 直到该品种数量为0 则种类减1
                freq[fruits[left]]-=1
                if freq[fruits[left]]==0:
                    count-=1
                left+=1
            #更新区间
            res=max(res,right-left+1)
        return res
            

1004. 最大连续1的个数 III

给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。

class Solution(object):
    def longestOnes(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        # 本质是确保窗口内0的个数小于等于k个
        left,right=0,0
        res=0
        # 分别计算0,1的个数
        count=[0,0]
        n=len(nums)
        while(right<n):
            count[nums[right]]+=1
            # 如果0的个数大于k 则移动左窗口到保持在窗口内0的个数为k的程度
            while(count[0]>k):
                count[nums[left]]-=1
                left+=1
            #跳出循环 说明此时窗口内0的数量等于k 更新窗口
            res=max(res,right-left+1)
            right+=1
        return res

76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        need = collections.defaultdict(int)
        for c in t:
            need[c] += 1
        needCnt = len(t)
        i = 0 #记录起始位置
        res = (0, float('inf'))  #用两个元素,方便之后记录起终点
        #三步骤:
        #1. 增加右边界使滑窗包含t
        for j,c in enumerate(s):
            if need[c] >0:
                needCnt -= 1
            need[c] -= 1 #这行放在外面不可以,看19行 need[c] == 0
        #2. 收缩左边界直到无法再去掉元素   !注意,处理的是i
            if needCnt == 0:
                while True:
                    c = s[i]
                    if need[c] == 0: #表示再去掉就不行了(need>0)
                        break
                    else:
                        need[c] += 1
                        i += 1
                if j-i < res[1] - res[0]:  #这里是否减一都可以,只要每次都是这样算的就行,反正最后也是输出子串而非长度
                    res = (i,j)
        #3. i多增加一个位置,准备开始下一次循环(注意这步是在 needCnt == 0里面进行的 )
                need[s[i]] += 1
                needCnt += 1    #由于 移动前i这个位置 一定是所需的字母,因此NeedCnt才需要+1
                i += 1
        return "" if res[1]>len(s) else s[res[0]: res[1]+1]

题解参考:https://leetcode-cn.com/problems/minimum-window-substring/solution/tong-su-qie-xiang-xi-de-miao-shu-hua-dong-chuang-k/

举报

相关推荐

0 条评论