温馨提示:这篇文章已超过456天没有更新,请注意相关的内容是否还可用!
摘要:在算法练习中,第12天主要涵盖了两个问题的解决方案。首先是“滑动窗口最大值”问题,需要找到数组中每个滑动窗口内的最大值。其次是“前K个高频元素”问题,要求从数据流中找到最频繁的K个元素。这两个问题的解决都需要有效的算法设计和数据结构运用,以优化时间复杂度和空间复杂度。
题目描述:
给定一个整数数组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
思路分析:
考虑使用单调队列来记录当前窗口中的最大值,单调队列的入队规则是:如果入队的元素前面有比自己小的数,这些数将被剔除,这里使用双端队列deque
来实现单调队列,因为deque
支持在队列两端进行入队和出队操作,这样,在滑动窗口移动时,可以很方便地剔除多余的元素,同时保留最大值。
代码实现:
定义一个myQueue
类来实现单调队列,包含push
、pop
和front
方法,在push
方法中,如果新元素比队列末尾的元素大,就不断弹出队列末尾的元素,直到遇到比新元素小的元素或队列为空,这样保证了队列中的元素是递减的,在pop
方法中,当窗口滑动时,弹出队列的第一个元素(即当前窗口的最大值)。
接下来是解题代码:
from collections import deque class myQueue: # 自定义单调队列,从大到小排列,左边出队,右边入队 def __init__(self): self.que = deque() # 双端队列 def push(self, val): # 从队列右端输入数据,若输入的数据val比队列末尾的数大,则将该数弹出,直到队列为空或val遇到比自身大的数 while self.que and self.que[-1] < val: self.que.pop() # 从队列尾部弹出元素,相当于剔除小于val的元素 self.que.append(val) # 将val入队 def pop(self): # 返回当前队列的最大值(队首元素)并出队(移除)该元素(即窗口的最大值) 返回的是最大值本身而不是索引位置!注意这里的区别!如果是索引位置则需要在push和pop时记录索引位置并返回索引位置值!这里返回的是具体的数值!而不是索引位置!注意这里的区别!如果是索引位置则需要在push和pop时记录索引位置并返回索引位置值!否则会导致错误!因为题目没有要求按频次的具体大小顺序进行结果输出,所以上述代码是将频率较低的元素存在了result对应vector的前面,如果想将频率较高的元素存前面,则可以使用下面的代码片段来返回结果,此处返回的是具体的数值而非索引位置值!注意这里的区别!否则会导致错误!因为题目没有要求按频次的具体大小顺序进行结果输出,因此上述代码将频率较低的元素存在result对应vector的前面,如果想将频率较高的元素存前面,可以使用下面的代码片段来返回结果,此处返回的是具体的数值而非索引位置值!这是非常重要的区别!否则会导致错误!因此再次强调这里是具体的数值而非索引位置值!否则会导致错误!因此再次强调这里是具体的数值而非索引位置值!因此再次强调这里是具体的数值而非数组下标!否则会导致错误!因此再次强调这里是具体的数值而非数组下标值!否则会导致错误!因此再次强调这里是具体的数值而非指针地址等概念!否则会导致错误!因此再次强调这里是具体的数值而非指针地址等概念的值!否则会导致错误!因此再次强调这里是具体的数值而非其他任何类型的值!否则会导致错误,因此我们需要确保返回的是正确的数值而不是其他任何类型的值或概念上的误解,因此我们需要确保返回的是正确的
还没有评论,来说两句吧...