0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

數(shù)據(jù)結構解決滑動窗口問題

jf_78858299 ? 來源:labuladong ? 作者:labuladong ? 2023-04-19 10:50 ? 次閱讀

前文用 [單調棧解決三道算法問題]介紹了單調棧這種特殊數(shù)據(jù)結構,本文寫一個類似的數(shù)據(jù)結構「單調隊列」。

也許這種數(shù)據(jù)結構的名字你沒聽過,其實沒啥難的,就是一個「隊列」,只是使用了一點巧妙的方法,使得 隊列中的元素全都是單調遞增(或遞減)的

「單調?!怪饕鉀Q Next Great Number 一類算法問題,而「單調隊列」這個數(shù)據(jù)結構可以解決滑動窗口問題。我們之前的爆文 [滑動窗口解題套路框架]) 講的滑動窗口算法是雙指針技巧的一種,是解決子串、子數(shù)組的通用技巧;而本文說的滑動窗口是比較具體的問題。

比如說力扣第 239 題「滑動窗口最大值」,難度 Hard

給你輸入一個數(shù)組nums和一個正整數(shù)k,有一個大小為k的窗口在nums上從左至右滑動,請你輸出每次窗口中k個元素的最大值。

函數(shù)簽名如下:

int[] maxSlidingWindow(int[] nums, int k);

比如說題目給出的一個示例:

圖片

一、搭建解題框架

這道題不復雜,難點在于如何在O(1)時間算出每個「窗口」中的最大值,使得整個算法在線性時間完成。這種問題的一個特殊點在于,「窗口」是不斷滑動的,也就是你得動態(tài)地計算窗口中的最大值。

對于這種動態(tài)的場景,很容易得到一個結論:

在一堆數(shù)字中,已知最值為A,如果給這堆數(shù)添加一個數(shù)B,那么比較一下AB就可以立即算出新的最值;但如果減少一個數(shù),就不能直接得到最值了,因為如果減少的這個數(shù)恰好是A,就需要遍歷所有數(shù)重新找新的最值 。

回到這道題的場景,每個窗口前進的時候,要添加一個數(shù)同時減少一個數(shù),所以想在 O(1) 的時間得出新的最值,不是那么容易的,需要「單調隊列」這種特殊的數(shù)據(jù)結構來輔助。

一個普通的隊列一定有這兩個操作:

class Queue {
    // enqueue 操作,在隊尾加入元素 n
    void push(int n);
    // dequeue 操作,刪除隊頭元素
    void pop();
}

一個「單調隊列」的操作也差不多:

class MonotonicQueue {
    // 在隊尾添加元素 n
    void push(int n);
    // 返回當前隊列中的最大值
    int max();
    // 隊頭元素如果是 n,刪除它
    void pop(int n);
}

當然,這幾個 API 的實現(xiàn)方法肯定跟一般的 Queue 不一樣,不過我們暫且不管,而且認為這幾個操作的時間復雜度都是 O(1),先把這道「滑動窗口」問題的解答框架搭出來:

int[] maxSlidingWindow(int[] nums, int k) {
    MonotonicQueue window = new MonotonicQueue();
    List

這個思路很簡單,能理解吧?下面我們開始重頭戲,單調隊列的實現(xiàn)。

二、實現(xiàn)單調隊列數(shù)據(jù)結構

觀察滑動窗口的過程就能發(fā)現(xiàn),實現(xiàn)「單調隊列」必須使用一種數(shù)據(jù)結構支持在頭部和尾部進行插入和刪除,很明顯雙鏈表是滿足這個條件的。

「單調隊列」的核心思路和「單調?!诡愃?,push方法依然在隊尾添加元素,但是要把前面比自己小的元素都刪掉:

class MonotonicQueue {
    // 雙鏈表,支持頭部和尾部增刪元素
    private LinkedList<Integer> q = new LinkedList<>();

    public void push(int n) {
    // 將前面小于自己的元素都刪除
        while (!q.isEmpty() && q.getLast() < n) {
            q.pollLast();
        }
        q.addLast(n);
    }

}

你可以想象,加入數(shù)字的大小代表人的體重,把前面體重不足的都壓扁了,直到遇到更大的量級才停住。

圖片

如果每個元素被加入時都這樣操作,最終單調隊列中的元素大小就會保持一個單調遞減的順序,因此我們的max方法可以可以這樣寫:

public int max() {
    // 隊頭的元素肯定是最大的
    return q.getFirst();
}

pop方法在隊頭刪除元素n,也很好寫:

public void pop(int n) {
    if (n == q.getFirst()) {
        q.pollFirst();
    }
}

之所以要判斷data.front() == n,是因為我們想刪除的隊頭元素n可能已經(jīng)被「壓扁」了,可能已經(jīng)不存在了,所以這時候就不用刪除了:

圖片

至此,單調隊列設計完畢,看下完整的解題代碼:

/* 單調隊列的實現(xiàn) */
class MonotonicQueue {
    LinkedList

有一點細節(jié)問題不要忽略,在實現(xiàn)MonotonicQueue時,我們使用了 JavaLinkedList,因為鏈表結構支持在頭部和尾部快速增刪元素;而在解法代碼中的res則使用的ArrayList結構,因為后續(xù)會按照索引取元素,所以數(shù)組結構更合適。

三、算法復雜度分析

讀者可能疑惑,push操作中含有 while 循環(huán),時間復雜度應該不是O(1)呀,那么本算法的時間復雜度應該不是線性時間吧?

單獨看push操作的復雜度確實不是O(1),但是算法整體的復雜度依然是O(N)線性時間。要這樣想,nums中的每個元素最多被push_backpop_back一次,沒有任何多余操作,所以整體的復雜度還是O(N)

空間復雜度就很簡單了,就是窗口的大小O(k)

其實我覺得,這種特殊數(shù)據(jù)結構的設計還是蠻有意思的,你學會單調隊列的使用了嗎?學會了給個三連?

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 數(shù)據(jù)結構

    關注

    3

    文章

    573

    瀏覽量

    40164
  • 隊列
    +關注

    關注

    1

    文章

    46

    瀏覽量

    10921
收藏 人收藏

    評論

    相關推薦

    什么是數(shù)據(jù)結構(Data Structrue)

    什么是數(shù)據(jù)結構(Data Structrue) 一 名詞術語數(shù)據(jù):描述客觀事物的數(shù)字,字符以及一切能夠輸入到計算機中,并且能夠被計算機程序處理的符號的集合。數(shù)據(jù)元素:數(shù)據(jù)這個
    發(fā)表于 02-09 17:17

    數(shù)據(jù)結構

    1.數(shù)據(jù)結構的概念 所謂數(shù)據(jù)結構是指由某一數(shù)據(jù)對象及該對象中所有數(shù)據(jù)成員之間的關系組成的集合。成員之間的關系有很多種,最常見的是前后件關系。 2.
    發(fā)表于 03-04 14:13

    常見的數(shù)據(jù)結構

    `數(shù)據(jù)結構在實際應用中非常常見,現(xiàn)在各種算法基本都牽涉到數(shù)據(jù)結構,因此,掌握數(shù)據(jù)結構算是軟件工程師的必備技能。一、什么是數(shù)據(jù)結構數(shù)據(jù)結構,直
    發(fā)表于 05-10 07:58

    數(shù)據(jù)結構教程,下載

    1. 數(shù)據(jù)結構的基本概念 2. 算法與數(shù)據(jù)結構3. C語言的數(shù)據(jù)類型及其算法描述要點4. 學習算法與數(shù)據(jù)結構的意義與方法
    發(fā)表于 05-14 17:22 ?0次下載
    <b class='flag-5'>數(shù)據(jù)結構</b>教程,下載

    基于參數(shù)化存儲結構滑動窗口IP核自動生成

    為解決目前高級綜合方法在處理滑動窗口程序時存在的存儲系統(tǒng)設計瓶頸問題,提出了參數(shù)化存儲體系結構模型.采用三級存儲層次,充分開發(fā)內層循環(huán)、外層循環(huán)的數(shù)據(jù)重用;采用
    發(fā)表于 01-27 14:32 ?19次下載

    GPIB命令的數(shù)據(jù)結構

    針對GPIB命令的結構,提出一種存儲GPIB命令的數(shù)據(jù)結構。根據(jù)GPIB命令的層次關系的特點,選擇數(shù)據(jù)結構中“樹”的概念來存儲GPIB命令結點;并考慮程序實現(xiàn)的效率問題以及管理維護
    發(fā)表于 02-10 16:20 ?70次下載

    什么是數(shù)據(jù)結構

    什么是數(shù)據(jù)結構 1、數(shù)據(jù)類型和數(shù)據(jù)結構·數(shù)據(jù)值:atomic data value: 不可再分解。如3、2、5等。nonatomicdata value: 可以再分解,其成分稱為
    發(fā)表于 08-13 13:56 ?1687次閱讀

    數(shù)據(jù)結構與算法

    全國C語言考試公共基礎知識點——數(shù)據(jù)結構與算法,該資料包含了有關數(shù)據(jù)結構與算法的全部知識點。
    發(fā)表于 03-30 14:27 ?0次下載

    數(shù)據(jù)結構

    數(shù)據(jù)結構PPT教程
    發(fā)表于 02-27 16:43 ?0次下載

    數(shù)據(jù)結構是什么_數(shù)據(jù)結構有什么用

    數(shù)據(jù)結構是計算機存儲、組織數(shù)據(jù)的方式。數(shù)據(jù)結構是指相互之間存在一種或多種特定關系的數(shù)據(jù)元素的集合。通常情況下,精心選擇的數(shù)據(jù)結構可以帶來更高
    發(fā)表于 11-17 14:45 ?1.6w次閱讀
    <b class='flag-5'>數(shù)據(jù)結構</b>是什么_<b class='flag-5'>數(shù)據(jù)結構</b>有什么用

    為什么要學習數(shù)據(jù)結構?數(shù)據(jù)結構的應用詳細資料概述免費下載

    本文檔的主要內容詳細介紹的是為什么要學習數(shù)據(jù)結構?數(shù)據(jù)結構的應用詳細資料概述免費下載包括了:數(shù)據(jù)結構在串口通信當中的應用,數(shù)據(jù)結構在按鍵監(jiān)測當中的應用
    發(fā)表于 09-11 17:15 ?13次下載
    為什么要學習<b class='flag-5'>數(shù)據(jù)結構</b>?<b class='flag-5'>數(shù)據(jù)結構</b>的應用詳細資料概述免費下載

    什么是數(shù)據(jù)結構?為什么要學習數(shù)據(jù)結構?數(shù)據(jù)結構的應用實例分析

    本文檔的主要內容詳細介紹的是什么是數(shù)據(jù)結構?為什么要學習數(shù)據(jù)結構?數(shù)據(jù)結構的應用實例分析包括了:數(shù)據(jù)結構在串口通信當中的應用,數(shù)據(jù)結構在按鍵
    發(fā)表于 09-26 15:45 ?14次下載
    什么是<b class='flag-5'>數(shù)據(jù)結構</b>?為什么要學習<b class='flag-5'>數(shù)據(jù)結構</b>?<b class='flag-5'>數(shù)據(jù)結構</b>的應用實例分析

    滑動窗口算法技巧

    說起滑動窗口算法,很多讀者都會頭疼。這個算法技巧的思路非常簡單,就是維護一個窗口,不斷滑動,然后更新答案么。LeetCode 上有起碼 10 道運用
    的頭像 發(fā)表于 04-19 10:55 ?924次閱讀
    <b class='flag-5'>滑動</b><b class='flag-5'>窗口</b>算法技巧

    NetApp的數(shù)據(jù)結構是如何演變的

    混合和多云部署模型是企業(yè)IT組織的新常態(tài)。隨著這些復雜的環(huán)境,圍繞數(shù)據(jù)管理的新挑戰(zhàn)出現(xiàn)了。NetApp的數(shù)據(jù)管理愿景是一種無縫連接不同的數(shù)據(jù)結構云,無論它們是私有環(huán)境、公共環(huán)境還是混合環(huán)境。數(shù)
    發(fā)表于 08-25 17:15 ?0次下載
    NetApp的<b class='flag-5'>數(shù)據(jù)結構</b>是如何演變的

    epoll的基礎數(shù)據(jù)結構

    一、epoll的基礎數(shù)據(jù)結構 在開始研究源代碼之前,我們先看一下 epoll 中使用的數(shù)據(jù)結構,分別是 eventpoll、epitem 和 eppoll_entry。 1、eventpoll 我們
    的頭像 發(fā)表于 11-10 10:20 ?827次閱讀
    epoll的基礎<b class='flag-5'>數(shù)據(jù)結構</b>