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
相关推荐
Mephisto.java23 分钟前
【力扣 | SQL题 | 每日四题】力扣2082, 2084, 2072, 2112, 180
sql·算法·leetcode
robin_suli24 分钟前
滑动窗口->dd爱框框
算法
丶Darling.26 分钟前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo52036 分钟前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法
jiyisuifeng19911 小时前
代码随想录训练营第54天|单调栈+双指针
数据结构·算法
꧁༺❀氯ྀൢ躅ྀൢ❀༻꧂1 小时前
实验4 循环结构
c语言·算法·基础题
新晓·故知1 小时前
<基于递归实现线索二叉树的构造及遍历算法探讨>
数据结构·经验分享·笔记·算法·链表
总裁余(余登武)2 小时前
算法竞赛(Python)-万变中的不变“随机算法”
开发语言·python·算法
Eric.Lee20212 小时前
音频文件重采样 - python 实现
人工智能·python·深度学习·算法·audio·音频重采样
huapiaoy2 小时前
Redis中数据类型的使用(hash和list)
redis·算法·哈希算法