4 前缀和、双端队列使用:子串

很多方法需要借助数据结构来操作;

1 数组

2 栈

3 队列

4 堆

5 链表

双端队列(deque,全称为double-ended queue)是一种特殊的线性数据结构,它允许在其两端进行添加和删除操作。在Python中,双端队列由标准库collections模块提供,类名为collections.deque。相比于列表,双端队列在两端执行插入和删除操作时更加高效,特别是对于大量数据的插入和删除操作,因为deque的底层实现是基于双向链表的,保证了这些操作的时间复杂度为O(1)。

双端队列因其高效的插入和删除特性,在多种场景下非常有用:

  • 队列和栈 : 可以当作先进先出(FIFO)的队列使用(使用appendpopleft),也可以作为后进先出(LIFO)的栈使用(使用appendpop)。
  • 滑动窗口: 在处理数组或序列问题时,如计算连续子数组的最大和、滑动平均等,deque可以方便地维持一个固定大小的窗口。
  • 浏览器导航 : 实现浏览器的前进和后退功能,其中前进历史可以用右侧添加,后退历史用左侧添加,通过popleftpop来模拟用户操作。
  • 表达式求值: 解析表达式时,可以使用deque来存储操作符栈。

总之,Python中的collections.deque是一个灵活且高效的数据结构,特别适合那些需要频繁在两端进行插入和删除操作的应用场景。

https://leetcode.cn/problems/subarray-sum-equals-k/

1 560. 和为 K 的子数组

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k的子数组的个数。子数组是数组中元素的连续非空序列。

示例 1:

复制代码
输入:nums = [1,1,1], k = 2
输出:2

示例 2:
输入:nums = [1,2,3], k = 3
输出:2
关键字: 连续子数组的和;
前缀和: 从前面某一个位置数据到当前位置的总和;
一个连续子数组的和 = 两个前缀和的差;

有点动态规划的影子。

1 设定一个字典用:到目前访问a这个下标,之前有多少个这样的前缀子串。

K :V, K 是到目前为止的前缀和, V:有多少个这样的前缀和

复制代码
class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        dict_cum = defaultdict(int)
        dict_cum[0] = 1
        # 前缀和
        cum_nums = 0
        res = 0
        for i,num in enumerate(nums):
            cum_nums += num

            # 想一下 dict_cum[cum_nums - k]: 到目前为止的所有前缀和;
            res += dict_cum.get(cum_nums-k,0)

            dict_cum[cum_nums] = dict_cum.get(cum_nums,0) + 1

        return res

2 239. 滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

示例 1:

复制代码
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

示例 2:

复制代码
输入:nums = [1], k = 1
输出:[1]

2.1 暴力破解

1 遍历数组;

2 固定长度为K窗口,查找最大值;

时间复杂度 O(NK);超时;

python 复制代码
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        slid_windows = nums[:k]
        max_list = [max(slid_windows)]
    
        for i in range(k,len(nums)):
            slid_windows.pop(0)
            slid_windows.append(nums[i])
            max_list.append(max(slid_windows))
        return max_list

2.2 双端队列方法

借助一个双端队列:队尾(left)保存之前 (小于)K 个最大值的排序;

队列功能:

1 保存索引;

2 队尾是当前访问的最大值; 这样每一次遍历数组中的元素,把队尾元素拿出来就是最大值了。

3 队是有序的(降序);

如何保证有序?

每次访问一个元素X,就从右到左访问队,如果队头小于X,弹出去;

python 复制代码
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        ans = []
        q = deque()

        for i,x in enumerate(nums):

            # 保证降序
            while q and nums[q[-1]]<=x:
                q.pop()
            # 把当前的加入队中
            q.append(i)
            # 看一下 最大值 是不是已经过界了, 如果最大值在窗口最左边,窗口滑动了,这个元素就要弹出去
            if i - q[0] >= k:
                q.popleft()
            # 保存最大值
            if i - k >= -1:
                ans.append(nums[q[0]])
        return ans
相关推荐
得物技术3 分钟前
得物社区搜推公式融合调参框架-加乘树3.0实战
算法
会员源码网19 小时前
使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)
后端·算法
木心月转码ing20 小时前
Hot100-Day10-T438T438找到字符串中所有字母异位词
算法
HelloReader20 小时前
Wi-Fi CSI 感知技术用无线信号“看见“室内的人
算法
颜酱1 天前
二叉树分解问题思路解题模式
javascript·后端·算法
qianpeng8971 天前
水声匹配场定位原理及实验
算法
董董灿是个攻城狮2 天前
AI视觉连载8:传统 CV 之边缘检测
算法
AI软著研究员2 天前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish2 天前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱2 天前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法