首页 > 其他分享 >代码随想录数组二刷:长度最小的子数组(滑动窗口)

代码随想录数组二刷:长度最小的子数组(滑动窗口)

时间:2024-07-20 23:40:36浏览次数:14  
标签:right 窗口 min 随想录 len 二刷 数组 hash left

代码随想录数组二刷:长度最小的子数组(滑动窗口)

leetcode209

在这里插入图片描述
这道题采用滑动窗口的思想去做。
实现滑动窗口,主要确定如下三点:

  1. 窗口内是什么?
  2. 如何移动窗口的起始位置?
  3. 如何移动窗口的结束位置?
    窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
    具体代码如下:
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        l = len(nums)
        left,right = 0,0
        min_len = float('inf')
        cur_sum = 0
        while right < l:
            cur_sum += nums[right]
            while cur_sum >= target:
                min_len = min(min_len, right - left + 1)
                cur_sum -= nums[left]
                left += 1
            right += 1
        return min_len if min_len!=float('inf') else 0

接下来来具体分析这个代码,因为是滑动窗口,那么这个窗口是怎么构成的呢,是不是就是left和right组成的区间长度,那么何时去计算这个长度,是不是区间里面的和大于等于target时候开始去计算长度。也就是:while cur_sum >= target,然后左边开始移动,移动的原因是因为这个和可能远超你要求的target,所以可以移动左边来缩小窗口。由于你左边移动了,就要把个值从总体的和剔除掉。那么啥时候退出这个内部循环呢。也就是求出的和小于target时候,就去移动右边界。
下面来看水果成篮这道题:

leetcode904

在这里插入图片描述
这道题也是采用滑动窗口去解决问题。在做这道题时候,要明白几个问题才能去做好这道题

  1. 窗口内是什么?
  2. 如何移动窗口的起始位置?
  3. 如何移动窗口的结束位置?

这道题窗口内就是能摘的树的数量。但是数组里面的数字相当于是标记一样,这里要用到哈希表去记录一下。因为最多两个篮子,所以种类最多是两种。当超过两个篮子时候,左边窗口开始移动,同时哈希表关于该项的值要减去1,如果该项的值为0,则删除这一项。
具体代码如下:

class Solution:
    def totalFruit(self, fruits: List[int]) -> int:
        count = collections.defaultdict(int)
        left,max_len,right = 0,0,0
        while right < len(fruits):
            count[fruits[right]] += 1
            while len(count) > 2:
                count[fruits[left]] -= 1
                if count[fruits[left]] == 0:
                    del count[fruits[left]]
                left += 1
            max_len = max(max_len, right - left + 1)
            right += 1
        return max_len

代码步骤解析

  1. 初始化变量

    • countdefaultdict(int),用于记录窗口内每种水果的数量。
    • leftright:窗口的左右边界。
    • max_len:记录遇到的最大窗口长度。
  2. 扩展窗口

    • 使用 right 指针遍历 fruits 数组,每次循环中将 fruits[right] 加入到窗口(即哈希表 count 中增加对应水果的计数)。
  3. 调整窗口大小

    • 当哈希表中的键(即水果类型)数量超过 2 时,开始移动 left 指针缩小窗口,直到窗口内的水果类型数不超过两种。
    • 如果某种水果的数量减到 0,则从哈希表中删除该水果。
  4. 更新最大长度

    • 在每次循环的末尾,更新 max_len 为当前窗口的长度(right - left + 1)和已记录的 max_len 中的较大值。
  5. 返回结果

    • 循环结束后,返回 max_len 作为最大可以摘的水果数量。

性能分析

  • 时间复杂度:O(N),其中 N 是 fruits 数组的长度。尽管内部有一个 while 循环来调整窗口大小,但每个元素最多被加入和删除一次。
  • 空间复杂度:O(1),虽然使用了哈希表,但由于最多只存储两种水果的计数,所以空间复杂度为常数。
    下面继续来看一道题;

leetcode76

在这里插入图片描述
这道题也是用滑动窗口+哈希表去做。首先s的长度小于t的长度是一定不满足的,直接返回空字符串即可。
外层while循环依旧控制窗口右边界,内层循环控制左边界。只不过这道题需要用到哈希表记录t对应字符个数。具体代码如下:

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        if len(s) < len(t):
            return ""
        hash_t = collections.defaultdict(int)
        hash_s = collections.defaultdict(int)
        min_len = float('inf')
        min_window = ""
        left,right,formed= 0,0,0
        for i in range(len(t)):
            hash_t[t[i]] += 1
        hash_t_lenth = len(hash_t)
        while right < len(s):
            hash_s[s[right]] += 1
            if s[right] in hash_t and hash_s[s[right]] == hash_t[s[right]]:
                formed += 1
            while  formed == hash_t_lenth:
                if right - left + 1 < min_len:
                    min_len = right - left + 1
                    min_window = s[left:right+1]
                hash_s[s[left]] -= 1
                if hash_s[s[left]] < hash_t[s[left]]:
                    formed -= 1
                left += 1
            right += 1
        return min_window

下面继续看几道滑动窗口相关的题目:

leetcode3

在这里插入图片描述
具体代码如下:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        left,right = 0,0
        maxlen = 0
        hashmap = collections.defaultdict(int)
        while right < len(s):
            hashmap[s[right]] += 1
            while hashmap[s[right]] > 1:
                hashmap[s[left]] -= 1
                if hashmap[s[left]] == 0:
                    del hashmap[s[left]]
                left += 1
            maxlen = max(maxlen, right - left + 1)
            right += 1
        return maxlen

标签:right,窗口,min,随想录,len,二刷,数组,hash,left
From: https://www.cnblogs.com/bathwind/p/18313964

相关文章

  • 代码随想录算法训练营第十七天 | 530.二叉搜索树的最小绝对差 、 501.二叉搜索树中的
    530.二叉搜索树的最小绝对差 题目:.-力扣(LeetCode)思路:中序遍历搜索二叉树,使用双指针来计算绝对值。代码:/***Definitionforabinarytreenode.*structTreeNode{*intval;*TreeNode*left;*TreeNode*right;*TreeNode():val(0),......
  • 代码随想录算法训练营第十五天 | 110.平衡二叉树、257. 二叉树的所有路径 、404.左叶
    110.平衡二叉树题目:.-力扣(LeetCode)思路:后序遍历计算高度代码:/***Definitionforabinarytreenode.*structTreeNode{*intval;*TreeNode*left;*TreeNode*right;*TreeNode():val(0),left(nullptr),right(nullptr){}*......
  • 代码随想录移除元素二刷
    代码随想录移除元素二刷leetcode27这道题思路的话可以这样去理解,用两个指针,一个慢指针,一个快指针。先让快指针往前面去探路,也就是去遍历数组,遇到不为val的值再去把该值赋值给nums[slow],slow指针+1,遇到为val的值,nums[slow]不做任何操作,继续移动fast指针。具体代码如下:classSo......
  • JAVA 数据结构 - 数组
    一、固定数组Arrays数组用来存储固定大小的同类型的元素;1、声明,初始化,访问int[]myIntArray;double[]myDoubleArr;String[]myStrArr;intsize=10;double[]myDoubleArr=newdouble[size];double[]myList={1.9,1.4,2.3,9.8};for(inti=0;i<myList.le......
  • 代码随想录算法训练营第33天 | 贪心4:452. 用最少数量的箭引爆气球、435. 无重叠区间
    代码随想录算法训练营第33天|贪心4:452.用最少数量的箭引爆气球、435.无重叠区间、763.划分字母区间452.用最少数量的箭引爆气球https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/description/代码随想录https://programmercarl.com/0452.用最......
  • 代码随想录day 31 用最少数量的箭引爆气球 | 无重叠区间 | 划分字母区间
    用最少数量的箭引爆气球用最少数量的箭引爆气球解题思路先根据数组中的第一个参数进行排序,之后通过记录最小右区间来判断是否重叠或者进入下个重叠区。贪心的思想是有重叠就尽可能地进行重叠,从而达到局部最优知识点重叠区间,贪心心得学会了如何判断和找寻重叠区间的方法无......
  • 嵌入式学习记录——C基础(数组与排序)
    数组与排序数组一维数组二维数组排序冒泡排序选择排序数组数组是由一个或者多个相同数据类型的数据组成的一个集合一维数组如果将数组看做一个坐标轴,一维数组则如同只有X坐标,每个数组中的元素内存地址都是连续的,当数据类型和首个元素a[0]确定时,后续a[i]依次递增......
  • 代码随想录算法训练营第31天 | 贪心3:134.加油站、135.分发糖果、860.柠檬水找零、406.
    代码随想录算法训练营第31天|贪心3:134.加油站、135.分发糖果、860.柠檬水找零、406.根据身高重建队列134.加油站https://leetcode.cn/problems/gas-station/description/代码随想录https://programmercarl.com/0134.加油站.html135.分发糖果https://leetcode.cn/problems......
  • [LeetCode] 977. 有序数组的平方
    有序数组的平方简单给你一个按非递减顺序排序的整数数组nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。示例1:输入:nums=[-4,-1,0,3,10]输出:[0,1,9,16,100]解释:平方后,数组变为[16,1,0,9,100]排序后,数组变为[0,1,9,16,100]示例2:输入:nums=[-7......
  • 代码随想录day4 | 24 两两交换链表节点 19 删除倒数第n个节点 142 环形链表
    24两两交换节点funcswapPairs(head*ListNode)*ListNode{ //思路涉及到链表增删改操作,优先考虑使用虚拟头节点此处为双指针加上虚拟头节点 ifhead==nil||head.Next==nil{ returnhead } vardummyHead=&ListNode{0,head} varprev=dummyHead forp......