python算法与数据结构---滑动窗口双指针

news/2024/5/20 9:45:23 标签: python, 算法, 数据结构, 双指针, 滑动窗口

学习目标

滑动窗口

209. 长度最小的子数组

https://leetcode.cn/problems/minimum-size-subarray-sum/description/
在这里插入图片描述

暴力解法

  • 目标是找子数组,暴力遍历所有的子数组

  • 枚举子数组的下标i,对于每个开始下标i:

    • 枚举子数组的结束下标j(i<=j)
    • 使得nums[i]到nums[j]的元素和大于等于s
    • 更新子数组的最小长度(j-i+1)
  • 优化点:

    • 前提:nums数组中全是正整数
    • 枚举子数组的结束下标时,如果nums[i]到nums[j]的元素和大于等于s时,中断对结束下标的枚举
python">class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        if not nums:
            return 0

        n = len(nums)
        ans = n + 1
        # 枚举子数组的开始下标i;
        for i in range(n):
            total = 0
            # 枚举子数组的结束下标j
            for j in range(i, n):
                total += nums[j]
                # 更新子数组的最小长度(j-i+1)
                if total >= target:
                    ans = min(ans, j - i + 1)
                    break
        if ans == n + 1:
            return 0
        else:
            return ans

滑动窗口

  • 定义两个指针start和end分别表示子数组(滑动窗口)的开始位置和结束位置,初始状态下都指向下标0;
  • 维护变量total存储子数组中的元素和(即从nums[start]到nums[end]的元素和)
  • 迭代:
    • 滑动窗口终止位置移动:在每一轮迭代的最后,将end右移,将nums[end]加到total
    • 滑动窗口起始位置移动:若total>=s,则更新子数组最小长度end-start+1,然后将nums[start]从total中减去并将start右移,直到total<s,同时不断更新子数组的最小长度
python">class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        if not nums:
            return 0

        n = len(nums)
        ans = n + 1
        # 滑动窗口的开始位置和结束位置
        start, end = 0, 0
        total = 0 
        while end < n:
            total += nums[end]
            while total >= target:
                ans = min(ans, end - start + 1)
                total -= nums[start]
                # 滑动窗口起始位置移动
                start += 1
            # 滑动窗口终止位置移动
            end += 1
        if ans == n + 1:
            return 0
        else:
            return ans

滑动窗口图解

在这里插入图片描述

  • 扩张窗口:为了找到一个可行解,找到了就不再扩张,因为扩张不再有意义;
  • 收缩窗口:在长度上优化该可行解,直到条件被破坏;
  • 继续寻找下一个可行解,然后再优化到不能优化

567. 字符串的排列

https://leetcode.cn/problems/permutation-in-string/description/
在这里插入图片描述
题目建模:

  • 无需全排列:排列不会改变字符串中每个字符的个数,所以只有两个字符串每个字符的个数均相等时,一个字符串才是另一个字符串的排列
  • 建模:s1的每个字符出现的次数,与s2某个子串的每种字符出现次数相同。

滑动窗口解法

  • 维护两个数组dic1和dic2,其中dic1用于统计s1中各个字符的个数,dic2用于统计当前遍历子串中的各个字符的个数;
  • 由于需要遍历的子串长度均为m1,我们可以使用一个固定长度为m1的滑动窗口来维护dic2;
  • 滑动窗口每向右滑动一次,就多统计一次进入窗口的字符,少统计一次离开窗口的字符。然后,判断dic1是否与dic2相等,若相等则意味着当前窗口内的子串是s1的排列之一。
python">class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        m1 = len(s1)
        m2 = len(s2)
        if m1 > m2:
            return False
        # 采用有序字典来比较,由于只包含小写字母,采用数组来模拟有序字典
        dic1 = [0] * 26
        dic2 = [0] * 26
        # 滑动窗口长度固定为m1
        for i in range(m1):
            dic1[ord(s1[i]) - ord('a')] += 1
            dic2[ord(s2[i]) - ord('a')] += 1
        
        if dic1 == dic2:
            return True
        
        # 滑动窗口每向右滑动一次,就多统计一次进入窗口的字符,少统计一次离开窗口的字符
        for i in range(m1, m2):
            dic2[ord(s2[i-m1]) - ord('a')] -= 1
            dic2[ord(s2[i]) - ord('a')] += 1
            if dic1 == dic2:
                return True
        return False
        

双指针

  • 滑动窗口有本质上是双指针,窗口的开始位置和结束位置便是两个指针,窗口的滑动对应指针的移动;
  • 双指针有时也叫快慢指针,在数组里是用两个整型代表下标,在链表里面是两个指针,一般能将O(N^2)的时间复杂度降为O(N);
  • 两个指针的位置一般在第一个元素和第二个元素或者第一个元素和最后一个元素,快指针在前“探路”,当符合某种条件快慢指针向前挪动。
  • 同向双指针,在同向双指针套路中,两个指针朝相同方向移动,但是快慢不同。
  • 反向双指针, 反向双指针中的两个指针反向而行。

11. 盛最多水的容器

https://leetcode.cn/problems/container-with-most-water/description/
在这里插入图片描述

双指针解法

  • 指针每一次移动,都意味着排除掉一根柱子;
  • 如何确定排除哪一根柱子。
    在这里插入图片描述
python">class Solution:
    def maxArea(self, height: List[int]) -> int:
        #双指针
        """
        1、设置两个指针,一个指向起始位置,一个指向末尾,则s = min(h[i],h[j])*(j-i);
        2、指针向内移动,移动高板,则面积肯定减少;
        3、移动矮板,面积可能增加
        4、直至指针相遇,返回面积最大值
        """
        #coding 
        i, j = 0, len(height)-1
        area = 0
        ans = 0
        while i < j:
            area = min(height[i],height[j]) * (j-i)
            ans = max(area,ans)
            if height[i] < height[j]:
                i += 1
            else:
                j -= 1
            
        return ans

http://www.niftyadmin.cn/n/5352033.html

相关文章

HarmonyOS --@state状态装饰器

在声明式UI中&#xff0c;是以状态驱动视图更新。 状态&#xff08;state&#xff09;&#xff1a;指驱动视图更新的数据&#xff08;被装饰器标记的变量&#xff09;。 试图&#xff08;view&#xff09;&#xff1a;基于UI描述渲染得到用户界面 State装饰器标记的变量必须初…

JavaScript中解锁Map和Set的力量

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ ​ ✨ 前言 ES6带来了Map和Set两个新的数据结构 - 它们分别用于存放键值对和唯一值。Map和Set提供了更…

晶振的基础知识

当谈论晶振时&#xff0c;我们通常指的是一种能够产生稳定且精确频率的元件&#xff0c;它在现代电子设备中发挥着关键的作用。从钟表到计算机&#xff0c;晶振无处不在&#xff0c;其稳定性和精确性对于确保设备正常运行至关重要。本文将深入探讨晶振的工作原理、应用领域、技…

【解决方法】git pull报错ssh: connect to host github.com port 22: Connection timed out

问题 git pull ssh: connect to host github.com port 22: Connection timed out fatal: Could not read from remote repository.解决方法 在C:\Users\username.ssh文件夹下新建config文件&#xff0c;填入以下文本&#xff08;如有则直接在文件最后一行新增&#xff09;&am…

避免灾难的良药:接口幂等性的架构秘术

文章目录 前言一、什么是幂等性&#xff1f;二、幂等性导致的原因三、非幂等性的危害四、哪些场景需要做幂等性设计五、常见的保证幂等的方式数据库层面代码层面 前言 我们经常会听到幂等性这个词&#xff0c;那什么是幂等性呢&#xff1f;为什么都在强调接口要做幂等性处理&a…

qemu调试kernel启动(从第一行汇编开始)

一、背景 大部分qemu调试kernel 都是讲解从start_kernel开始设置断点&#xff0c;然后开启调试&#xff1b; 但是我们熟悉linux启动流程的伙伴肯定知道&#xff0c;在start_kernel之前还有一段汇编&#xff0c;包括初始化页表及mmu等操作&#xff0c; 这部分如何调试呢&#x…

【vue2】路由之 Vue Router

文章目录 一、安装二、基础使用1、简单的示例2、动态路由2.1 定义动态路径参数2.2 获取动态路径的参数2.3 捕获所有路由 3、嵌套路由4、编程式的导航4.1 router.push4.2 router.replace4.3 router.go(n) 5、命名路由6、重定向 三、进阶1、导航守卫1.1 全局前置守卫1.2 全局后置…

C语言推荐新手学习吗?

今日话题&#xff0c;C语言推荐新手学习吗&#xff1f;我自己当年是从BASIC入门编程的&#xff0c;回顾起来&#xff0c;BASIC的确是一门非常容易入门的语言。它让初学者能够专注于编写程序本身&#xff0c;而不必过多关注细节。Pascal也是一门较易入门的语言&#xff0c;比C语…