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
相关推荐
ssshooter18 分钟前
小猫都能懂的大模型原理 1 - 深度学习基础
人工智能·算法·llm
慕容青峰1 小时前
【LeetCode 1925. 统计平方和三元组的数目 题解】
c++·算法·leetcode
冰西瓜6001 小时前
动态规划(一)算法设计与分析 国科大
算法·动态规划
TL滕1 小时前
从0开始学算法——第十一天(字符串基础算法)
笔记·学习·算法
roman_日积跬步-终至千里2 小时前
【计算机算法与设计(10)】习题:苹果买卖问题——分治法的经典应用
算法
deepdata_cn2 小时前
模型预测控制(MPC)算法
算法
独自破碎E2 小时前
如何用最短替换让字符串变平衡?
java·开发语言·算法·leetcode
Jasmine_llq2 小时前
《P1082 [NOIP 2012 提高组] 同余方程》
算法·数学建模·质因数分解(试除法)·快速幂(模幂运算)·欧拉函数计算·基于质因数分解
算家计算2 小时前
AI真的懂你!阿里发布Qwen3-Omni-Flash 全模态大模型:超强交互,人设任选
人工智能·算法·机器学习
l1t2 小时前
利用Duckdb求解Advent of Code 2025第9题 最大矩形面积
数据库·sql·算法·duckdb·advent of code