Sliding Window Maximum

2023-05-16

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the knumbers in the window. Each time the sliding window moves right by one position.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.


Window position                Max
---------------               -----
[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
  

Therefore, return the max sliding window as [3,3,5,5,6,7].

Note: 
You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array.

Follow up:
Could you solve it in linear time?

这是一道非常有意思的题目。首先思路非常多,可以利用的数据结构也很多。

首先考虑暴力解法。即对每个sliding window都求最大值,复杂度为O(nk)。

下面考虑优化,对于求最大值,最小值,有一个非常好的数据结构,就是堆,这里需要在移动窗口的时候删除元素,如果用普通堆来做删除的复杂度为O(n)。显然不合适。这时候hashheap就可以派上用场,O(logk)时间求最大值,O(logk)时间删除元素。复杂度为O(nlogk)。空间复杂度为O(k)。代码如下:


class Solution:
    """
    @param nums: A list of integers.
    @return: The maximum number inside the window at each moving.
    """
    def maxSlidingWindow(self, nums, k):
        if not nums or len(nums) < k:
            return []
        res = []
        heap = HashHeap('max')
        for i in xrange(k):
            heap.add(nums[i])
        for i in xrange(k, len(nums)):
            res.append(heap.top())
            heap.delete(nums[i - k])
            heap.add(nums[i])
        res.append(heap.top())
        return res
       
class Node(object):
    """
    the type of class stored in the hashmap, in case there are many same heights
    in the heap, maintain the number
    """
    def __init__(self, id, num):
        self.id = id #id means its id in heap array
        self.num = num #number of same value in this id
        
class HashHeap(object):
    def __init__(self, mode):
        self.heap = []
        self.mode = mode
        self.size = 0
        self.hash = {}
    def top(self):
        return self.heap[0] if len(self.heap) > 0 else 0
        
    def contain(self, now):
        if self.hash.get(now):
            return True
        else:
            return False
        
    def isempty(self):
        return len(self.heap) == 0
        
    def _comparesmall(self, a, b): #compare function in different mode
        if a <= b:
            if self.mode == 'min':
                return True
            else:
                return False
        else:
            if self.mode == 'min':
                return False
            else:
                return True
    def _swap(self, idA, idB): #swap two values in heap, we also need to change
        valA = self.heap[idA]
        valB = self.heap[idB]
        
        numA = self.hash[valA].num
        numB = self.hash[valB].num
        self.hash[valB] = Node(idA, numB)
        self.hash[valA] = Node(idB, numA)
        self.heap[idA], self.heap[idB] = self.heap[idB], self.heap[idA]
    
    def add(self, now):  #the key, height in this place
        self.size += 1
        if self.hash.get(now):
            hashnow = self.hash[now]
            self.hash[now] = Node(hashnow.id, hashnow.num + 1)
        else:
            self.heap.append(now)
            self.hash[now] = Node(len(self.heap) - 1,1)
            self._siftup(len(self.heap) - 1)
            
    def pop(self):  #pop the top of heap
        self.size -= 1
        now = self.heap[0]
        hashnow = self.hash[now]
        num = hashnow.num
        if num == 1:
            self._swap(0, len(self.heap) - 1)
            self.hash.pop(now)
            self.heap.pop()
            self._siftdown(0)
        else:
            self.hash[now] = Node(0, num - 1)
        return now
        
    def delete(self, now):
        self.size -= 1
        hashnow = self.hash[now]
        id = hashnow.id
        num = hashnow.num
        if num == 1:
            self._swap(id, len(self.heap)-1) #like the common delete operation
            self.hash.pop(now)
            self.heap.pop()
            if len(self.heap) > id:
                self._siftup(id)
                self._siftdown(id)
        else:
            self.hash[now] = Node(id, num - 1)
            
    def parent(self, id):
      if id == 0:
        return -1

      return (id - 1) / 2

    def _siftup(self,id):
        while abs(id -1)/2 < id :  #iterative version
            parentId = (id - 1)/2 
            if self._comparesmall(self.heap[parentId],self.heap[id]):
                break
            else:
                self._swap(id, parentId)
            id = parentId
                
    def _siftdown(self, id): #iterative version
        while 2*id + 1 < len(self.heap):
            l = 2*id + 1
            r = l + 1
            small = id
            if self._comparesmall(self.heap[l], self.heap[id]):
                small = l
            if r < len(self.heap) and self._comparesmall(self.heap[r], self.heap[small]):
                small = r
            if small != id:
                self._swap(id, small)
            else:
                break
            id = small       

继续考虑是否可以优化,题目提示能否线性时间解决,其实这就比较tricky了,甚至提示使用deque,我也没有想出特别好的对策。其实这题应该想到对于这种求最大值的题目,单调队列是一个很好的选择,和单调栈类似,单调队列还有一个比较好的功能是:可以从头部删除元素,也就是对于过期的头部元素,可以比较及时的删除。那具体怎么做呢?

是单调递增队列还是单调递减队列?首先我们的元素增加都使从后段增加,队列尾部一般都是新增加的元素,我们无法保证它最大,那么选用单调递减队列,使其

头部是最大元素不失为一个很好的选择,之后我们继续思考,什么情况下进行增删,首先队首元素虽然是最大值,但是如果窗口移动后,它不在窗口内,则需要删除这个元素,每次窗口只移动一格,所以每次最多删除一个元素。另外我们每次增加新元素时,如果队列里有比它小的历史元素时,则这些元素本身不再有可能成为最大值,所以删除它们保持队列的单调递减性。单调栈和单调队列都有一个地方需要注意,就是相等时如何操作,如果队列里有元素和当前元素相等,我们是否需要删除,思考一下,其实应该删除,对于求最大值的情况,如果i已经进入窗口内,如果i对应的元素是这个窗口的最大值,前面那个和它相等的历史元素也就失效了。

注意和单调栈非常类似,单调队列存的同样是index。空间复杂度O(n),时间复杂度O(n),代码如下:


class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        if not nums or len(nums) < k:
            return []
        #O(n), deque, you must can
        dq = collections.deque()
        res = []
        for i in xrange(len(nums)):
            if dq and dq[0] < i - k + 1: #the element out of range
                dq.popleft()
            while dq and nums[dq[-1]] <= nums[i]: #the element impossible to be the maximum value in deque
                dq.pop()
            dq.append(i)
            if i > k - 2:
                res.append(nums[dq[0]])
        return res  

 

转载于:https://www.cnblogs.com/sherylwang/p/5655536.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Sliding Window Maximum 的相关文章

  • 在WPF中使用动画改变窗口大小

    我正在寻找一种方法来动画调整窗口大小 假设我有一个高度 300和宽度 300的窗口 我有2个按钮 当我单击第一个按钮时 窗口大小必须更改为高度 600并且宽度 600 当我单击另一个按钮时 窗口大小必须恢复到原始大小 我可以简单地更改高度和
  • Activity 已泄漏窗口

    在我的启动屏幕中 我做了它 以便它检测 wifi 或 3g 是否启用 如果不是 则会出现一个对话框屏幕提示用户退出并打开其中一个 如果它打开 则代码将继续 我的 logcat 中不断收到有关我的活动有泄漏窗口的错误 我不知道如何解决这个问题
  • 打开带有动态内容的窗口

    是否可以从 PHP 打开一个具有预定义内容的窗口 很明显 您可以从框架现有页面的 javascript 链接打开一个窗口 或者仅从引用现有页面的常规 a 标记执行 target blank 但我正在生成一些内容 并希望在新链接中打开该内容
  • Firefox 打开新选项卡而不是弹出窗口? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我发现在最新版本的 Firefox 中 添加了一个名为 在新选项卡中打开新窗口 的设置 当我保持打开状态时 所有弹出窗口 使用打开的jav
  • 当没有其他窗口打开时,System.Windows.Window.ShowDialog() 出现意外行为。知道为什么吗?

    当我的 WPF MVVM 应用程序尝试在主窗口启动之前显示两个连续的错误对话框窗口时 我发现了这一点 经过一些努力 确定第一个窗口后 应用程序进入循环 第二个错误对话框从未出现 我解决了这个问题 但我希望有人能启发我为什么会发生这种情况 看
  • 双击标题栏时如何知道窗口是否最小化?

    This image is from SystemPreferences gt Appearance 我想知道如何以编程方式获取该值 我问这个问题是因为我正在绘制一个带有自定义标题栏的窗口 并且我希望它 在行为上 尽可能类似于普通 非自定义
  • 如何在.NET 中获取当前窗口句柄计数和窗口句柄限制?

    我想在C 中获取当前窗口句柄数和系统范围的窗口句柄限制 我该怎么办 如果你读过 Raymond Chen 的帖子 你可能会像我一样觉得它很烦人 您只是 可能做错了什么 因为您正在做 Windows 无法完成的事情 在我的应用程序中 当用户第
  • 无法打开目标 = 空白的 Electron webview 链接

    我正在使用 Electron 我有一个显示外部网站的 webview 但我无法成功显示通常由该网站上的链接打开且目标 blank 的附加窗口 a href mentions html target blank Mentions l gale
  • 如何正确处理在node-webkit中打开_blank窗口的链接?

    我正在尝试使用new win policy事件来处理打开新窗口的链接点击 https github com rogerwang node webkit wiki Window new win policy https github com
  • Android 在屏幕上定位元素

    我有一个列表视图 当用户按下按钮时 我想收集按钮的坐标 并将编辑文本放置在屏幕上的按钮上方 当用户单击屏幕上的任何其他位置时 编辑文本将消失 并且它将触发一个使用用户在框中输入的数据的方法 我该如何去做这样的事情呢 我想要类似于 Quick
  • 如何检测并突出显示鼠标悬停时的矩形

    我在 C net 中创建了一个 Windows 应用程序控件 以图形模式显示一些对象 为此 我根据列表中的项目数量创建了一个矩形 并使用 Control OnPaint 事件将其绘制在控件上 现在 如果鼠标悬停在该矩形上 我想突出显示该矩形
  • 如何在 Windows 中获取和设置系统音量

    我想使用 unity 和 c 将键盘点击时的操作系统音量设置为一定水平 例如我想将 Windows 音量 不是 unity 设置为 70 我该怎么做 void Update if Input GetKeyDown KeyCode A Set
  • 何时引发 Window.SourceInitialized 事件

    我能保证Window SourceInitialized事件总是会在Window Loaded事件 我需要HwndSource在我的中进一步处理的对象Window Loaded 事件处理程序我不确定到那时这是否总是可用 以下是您可以预期的事
  • 如何创建一个没有边框且只能通过手柄调整大小的 WPF 窗口?

    如果你设置ResizeMode CanResizeWithGrip 在 WPF 上Window然后右下角会出现一个调整大小的夹点 如下 如果你设置WindowStyle None 标题栏也会消失 但灰色斜边仍然保留 直到您设置ResizeM
  • 如何处理 Tkinter 中的窗口关闭事件?

    如何在 Python Tkinter 程序中处理窗口关闭事件 用户单击 X 按钮 Tkinter 支持一种称为协议处理程序 http web archive org web 20201111215134 http effbot org tk
  • MacVim:跨窗口共享命名寄存器?

    我想跨 MacVim 窗口共享命名寄存器缓冲区 就像我在单个实例中跨缓冲区一样 换句话说 假设我标记了一个位置 m 然后去其他地方 我将一些文本拉入寄存器 a 从当前点到 m a m 然后我转到另一个窗口 不 我不是指同一窗口中的另一个分割
  • 计算 Windows 10 上第 3 方窗口的标题栏按钮的总宽度

    我最初的方法是使用GetSystemMetrics with SystemMetric SM CXSIZE以及一些基于可用按钮的简单数学计算 乘以 3 或乘以 1 通过WindowStyle DllImport user32 dll pri
  • Selenium Web 驱动程序如何知道新窗口何时打开,然后恢复执行

    我在使用 Selenium Web 驱动程序自动化 Web 应用程序时遇到问题 该网页有一个按钮 单击该按钮会打开一个新窗口 当我使用以下代码时 它会抛出OpenQA Selenium NoSuchWindowException No wi
  • Python:如何从另一个程序窗口获取文本标签?

    我想使用 Python 从另一个程序读取文本标签 我想我必须使用 WM GETTEXT 但我不知道如何使用 并且在互联网上找不到任何内容 我的程序获取活动窗口 但不读取文本标签 所以我希望有人可以帮助我 编辑 我添加了缓冲区和 SendMe
  • 跨 HTML 窗口调用 Javascript 函数

    根据this https stackoverflow com questions 87359 can i pass a javascript variable to another browser window页面我应该能够调用子窗口的参数

随机推荐

  • proxmox集群节点崩溃处理

    问题描述 在现有集群加入一个物理节点 xff0c 接着再此节点创建ceph监视器 创建OSD 从宿主机系统执行ceph osd tree查看状态 xff0c 创建起来的几个OSD状态都正常 xff08 up xff09 xff0c 从pro
  • debian笔记本电源管理

    kde下面使用kpowersave工具 xff0c 实现suspend和hibernate还需要pm ultis包 此时可以通过root权限pm suspend和pm hibernate实现to ram和to disk 普通用户用kpowe
  • 发挥Squid优势,TCP_HIT变成TCP_MEM_HIT

    192 168 10 139 15 Dec 2011 16 49 37 43 0800 34 GET http www jian com p w picpaths shufa jpg HTTP 1 0 34 200 95900 34 34
  • linux默认有回收站吗,linux下默认删除文件到回收站(bash实现)

    fedora下总是会把文件不小心删除了 xff0c 所以下面的脚本把实现 xff1a 文件删除默认移动到自己的回收站里面 功能 xff1a 脚本实现删除文件或者目录到 waste 自己定义 脚本附带文件名或者目录名 xff0c 则默认代表
  • EXCEL复制死机的问题

    最近发现好几例excel复制死机的现象 xff0c 特总结了一下解决方法 基本上就是下面几种 xff1a 可以供大家参考 1 剪贴板的问题 xff0c 与迅雷等监视剪贴板的软件相关 打开 配置 监视 监视剪贴板 xff0c 取消这个勾选 x
  • Transport endpoint is not connected 报错

    在android中做在线升级程序 xff0c 在http请求数据时 xff0c 出现如下错误 xff1a java net SocketTimeoutException Transport endpoint is not connected
  • Ubuntu下Qt自动退出

    一直在使用Qt xff0c 真的被它强大的功能 漂亮的界面深深吸引了 不过最近遇到了一件非常让人不爽的事情 xff0c 就是在Qt下创建文件的时候会自动 xff0c 而且没有代码提示功能 想想吧 xff0c 这是多么令人头痛 xff0c 没
  • 洛谷 P1233 【木棍加工】题解

    算法 xff1a 排序 xff0c DP xff08 最长上升子序列 xff09 前言 xff1a 此题的数据非常水 xff0c 这里给予一组 hack 数据 xff1a 21 96 25 1 9 39 19 87 51 7 61 11 1
  • C# 修改电脑DNS和IP方法

    lt summary gt 将IP xff0c DNS设置为自动获取 lt summary gt private void setDHCP string doscmd 61 34 netsh interface ip set address
  • 使用Java实现串口通信(二)

    1 写在前面 距离上一篇文章 使用Java实现串口通信 已经过去快两年的时间了 xff0c 在此期间收到了很多读者的反馈 xff0c 很高兴可以帮助到这么多人 xff0c 根据收到的反馈 xff0c 我对代码逻辑进行了优化整理 xff0c
  • MSMG ToolKit v11.2 DL

    友情提醒一下 xff0c 建议使用原版 精简操作系统要是被后门 看不懂英文的可以百度翻译 xff0c 时间久了就明白嘛意思了 无非就那几个单词 如真要使用汉化版 xff0c 优化版的 看好你的核心bin文件夹 MSMG ToolKit By
  • Flutter之使用overlay显示悬浮控件

    Overlay与OverlayEntry Overlay是一个Stack的widget xff0c 可以将overlay entry插入到overlay中 xff0c 使独立的child窗口悬浮于其他widget之上 因为Overlay本身
  • 七夕快到了!表白小程序制作详解,撩翻你的女神!

    大家可能都会在抖音上刷过 xff0c 那种表白小程序 xff0c 但在我看来表白还是亲口说出来比较好 xff0c 这类小程序只适合在平常的一些小节日给对方一个惊喜 话不多说 xff0c 现在进入正题 xff1a 首先 xff0c 要在电脑上
  • Android Studio更改项目SDK的版本

    Elipse 中的安卓项目 xff0c 在Android Studio中可以通过File gt new gt Import Project的方法建立起来 但是有时候需要用到更改项目的API Level xff0c 下面的操作步骤为更改方法
  • java使用POI操作XWPFDocument 生成Word实战(一)【比较详细的】

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 注 xff1a 我使用的word 2016 功能简介 xff1a xff08 1 xff09 使用jsoup解析html得到我用来生成word的文本 xff08 这个你们可
  • HTML加载本地图片

    lt DOCTYPE html gt lt html gt lt body gt lt img src 61 34 file C Users Administrator Desktop 1 jpg 34 gt lt body gt lt h
  • navicat mysql 连接本地 忘记密码 查看密码 操作

    https jingyan baidu com article 454316ab4e9e65f7a7c03ad1 html 转载于 https www cnblogs com yzw23333 p 9510990 html
  • 巧用“记事本” 让病毒白白运行

    电脑中毒后 xff0c 许多朋友会打开 进程管理器 xff0c 将几个不太熟悉的程序关闭掉 xff0c 但有时会碰到这种情况 xff1a 关掉一个 xff0c 再去关闭另外一个时 xff0c 刚才关闭的那个马上又运行了 再从注册表里先把启动
  • mmap如何使用?

    蓝森林 http www lslnet com 2006年4月24日 18 41 对Linux内核内存管理搞了好久了 xff0c 其中对于mmap如何使用 xff0c 有很长一段时间存在疑惑 xff0c 后来在看Linux进程间通信机制的时
  • Sliding Window Maximum

    Given an array nums there is a sliding window of size k which is moving from the very left of the array to the very righ