日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

滑动窗口—最值问题

發(fā)布時(shí)間:2024/4/15 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 滑动窗口—最值问题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目一:劍指 Offer 59 - II. 隊(duì)列的最大值

問題描述

請(qǐng)定義一個(gè)隊(duì)列并實(shí)現(xiàn)函數(shù) max_value 得到隊(duì)列里的最大值,要求函數(shù)max_value、push_back 和 pop_front 的均攤時(shí)間復(fù)雜度都是O(1)。若隊(duì)列為空,pop_front 和 max_value?需要返回 -1。

輸入:?

  • ["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
  • [[],[1],[2],[],[],[]]

輸出:?[null,null,null,2,1,2]

算法思路

我們知道對(duì)于一個(gè)普通隊(duì)列,push_back 和 pop_front 的時(shí)間復(fù)雜度都是O(1),因此我們直接使用隊(duì)列的相關(guān)操作就可以實(shí)現(xiàn)這兩個(gè)函數(shù)。對(duì)于 max_value 函數(shù),我們通常會(huì)這樣思考,即每次入隊(duì)操作時(shí)都更新最大值:

但是當(dāng)出隊(duì)時(shí),這個(gè)方法會(huì)造成信息丟失,即當(dāng)最大值出隊(duì)后,我們無法知道隊(duì)列里的下一個(gè)最大值。

為了解決上述問題,我們只需記住當(dāng)前最大值出隊(duì)后,隊(duì)列里的下一個(gè)最大值即可。具體方法是使用一個(gè)雙端隊(duì)列 deque,在每次入隊(duì)時(shí),如果 deque隊(duì)尾元素小于即將入隊(duì)的元素 value,則將小于 valuevalue 的元素全部出隊(duì)后,再將 valuevalue 入隊(duì);否則直接入隊(duì)。這時(shí),輔助隊(duì)列 deque 隊(duì)首元素就是隊(duì)列的最大值。

上段文字來源:https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/solution/ru-he-jie-jue-o1-fu-za-du-de-api-she-ji-ti-by-z1m/

class MaxQueue {//保存隊(duì)列所有數(shù)據(jù)Deque<Integer> dq = new LinkedList<Integer>();//保存隊(duì)列中后出隊(duì)的最大值Deque<Integer> decrease = new LinkedList<Integer>();public MaxQueue() {}public int max_value() {return this.dq.isEmpty()?-1:this.decrease.peekFirst();}public void push_back(int value) {//如果 deque隊(duì)尾元素小于即將入隊(duì)的元素 value,則將小于 valuevalue 的元素全部出隊(duì)后,再將 valuevalue 入隊(duì)while(!this.decrease.isEmpty() && this.decrease.peekLast() < value){this.decrease.removeLast();}this.decrease.offerLast(value);this.dq.offerLast(value);}public int pop_front() {int res = this.dq.isEmpty()?-1:this.dq.peekFirst();if(!this.dq.isEmpty())this.dq.removeFirst();//如果此次出隊(duì)的是剩余隊(duì)列中最大元素,則在最大值隊(duì)列中將該元素彈出if(!this.decrease.isEmpty() && res == this.decrease.peekFirst()){this.decrease.removeFirst();} return res;} }

題目二:155. 最小棧

問題描述

設(shè)計(jì)一個(gè)支持 push ,pop ,top 操作,并能在常數(shù)時(shí)間內(nèi)檢索到最小元素的棧。

  • push(x) —— 將元素 x 推入棧中。
  • pop()?—— 刪除棧頂?shù)脑亍?/li>
  • top()?—— 獲取棧頂元素。
  • getMin() —— 檢索棧中的最小元素

輸入:

  • ["MinStack","push","push","push","getMin","pop","top","getMin"]
  • [[],[-2],[0],[-3],[],[],[],[]]

輸出:

  • [null,null,null,null,-3,null,0,-2]

算法思路

借用一個(gè)輔助棧min_stack,用于存獲取stack中最小值。

  • push()方法: 每當(dāng)push()新值進(jìn)來時(shí),如果 小于等于 min_stack棧頂值,則一起push()到min_stack,即更新了棧頂最小值;
  • pop()方法: 判斷將pop()出去的元素值是否是min_stack棧頂元素值(即最小值),如果是則將min_stack棧頂元素一起pop(),這樣可以保證min_stack棧頂元素始終是stack中的最小值。
  • getMin()方法: 返回min_stack棧頂即可。

min_stack作用分析:

  • min_stack等價(jià)于遍歷stack所有元素,把升序的數(shù)字都刪除掉,留下一個(gè)從棧底到棧頂降序的棧
  • 相當(dāng)于給stack中的降序元素做了標(biāo)記,每當(dāng)pop()這些降序元素,min_stack會(huì)將相應(yīng)的棧頂元素pop()出去,保證其棧頂元素始終是stack中的最小元素。

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度 O(1) :壓棧、出棧、獲取最小值的時(shí)間復(fù)雜度都為 O(1) 。
  • 空間復(fù)雜度 O(N) :包含 N 個(gè)元素輔助棧占用線性大小的額外空間。
class MinStack {Deque<Integer> stack = new LinkedList<Integer>();Deque<Integer> minValueStack = new LinkedList<Integer>();/** initialize your data structure here. */public MinStack() {}public void push(int x) {stack.offerLast(x);//如果 小于等于 min_stack棧頂值,則一起push()到min_stack,即更新了棧頂最小值;if(minValueStack.isEmpty() || x <= minValueStack.peekLast())minValueStack.offerLast(x);}public void pop() {int num = 0;if(!stack.isEmpty()){num = stack.peekLast();stack.removeLast();//將pop()出去的元素值是否是min_stack棧頂元素值(即最小值),如果是則將min_stack棧頂元素一起pop(),這樣可以保證min_stack棧頂元素始終是stack中的最小值if(!minValueStack.isEmpty() && num == minValueStack.peekLast())minValueStack.removeLast();}}public int top() {return stack.peekLast();}public int getMin() {return minValueStack.isEmpty()?Integer.MIN_VALUE:minValueStack.peekLast();} }/*** Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(x);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();*/

題目三:239. 滑動(dòng)窗口最大值

問題描述

給你一個(gè)整數(shù)數(shù)組 nums,有一個(gè)大小為?k?的滑動(dòng)窗口從數(shù)組的最左側(cè)移動(dòng)到數(shù)組的最右側(cè)。你只可以看到在滑動(dòng)窗口內(nèi)的 k?個(gè)數(shù)字。滑動(dòng)窗口每次只向右移動(dòng)一位。返回滑動(dòng)窗口中的最大值。比如輸入:nums = [1,3,-1,-3,5,3,6,7], k = 3,輸出:[3,3,5,5,6,7]

  • 滑動(dòng)窗口的位置 ? ? ? ? ? ? ? ?最大值
  • --------------- ? ? ? ? ? ? ? -----
  • [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

算法思路

這個(gè)題目,算是很經(jīng)典的題目,我們的滑動(dòng)窗口主要分為兩種,一種的可變長(zhǎng)度的滑動(dòng)窗口,一種是固定長(zhǎng)度的滑動(dòng)窗口,這個(gè)題目算是固定長(zhǎng)度的代表。今天我們用雙端隊(duì)列來解決我們這個(gè)題目,學(xué)會(huì)了這個(gè)題目的解題思想你可以去解決一下兩道題目 劍指 Offer 59 - II. 隊(duì)列的最大值,155. 最小棧,雖然這兩個(gè)題目和該題類型不同,但是解題思路是一致的,都是很不錯(cuò)的題目,我認(rèn)為做題,那些考察的很細(xì)的,解題思路很難想,即使想到,也不容易完全寫出來的題目,才是能夠大大提高我們編碼能力的題目,希望能和大家一起進(jìn)步。這個(gè)題目我們用到了雙端隊(duì)列,隊(duì)列里面保存的則為每段滑動(dòng)窗口的最大值。我們先來了解下雙端隊(duì)列吧,隊(duì)列我們都知道,是先進(jìn)先出,雙端隊(duì)列呢?既可以從隊(duì)頭出隊(duì),也可以從隊(duì)尾出隊(duì),則不用遵循先進(jìn)先出的規(guī)則。下面我們通過一個(gè)動(dòng)畫來了解一下吧。

?

好啦,我們了解雙端隊(duì)列是什么東東了,下面我們?cè)偻ㄟ^一個(gè)動(dòng)畫,來看一下代碼的執(zhí)行過程吧,相信各位一下就能夠理解啦。我們就通過題目中的例子來表述。nums = [1,3,-1,-3,5,3,6,7], k = 3

?

不知道通過上面的例子能不能給各位描述清楚,如果不能的話,我再加把勁,各位看官,請(qǐng)接著往下看。我們將執(zhí)行過程進(jìn)行拆解:

  • 想將我們第一個(gè)窗口的所有值存入單調(diào)雙端隊(duì)列中,單調(diào)隊(duì)列里面的值為單調(diào)遞減的。如果發(fā)現(xiàn)隊(duì)尾元素小于要加入的元素,則將隊(duì)尾元素出隊(duì),直到隊(duì)尾元素大于新元素時(shí),再讓新元素入隊(duì),目的就是維護(hù)一個(gè)單調(diào)遞減的隊(duì)列。
  • 我們將第一個(gè)窗口的所有值,按照單調(diào)隊(duì)列的規(guī)則入隊(duì)之后,因?yàn)殛?duì)列為單調(diào)遞減,所以隊(duì)頭元素必為當(dāng)前窗口的最大值,則將隊(duì)頭元素添加到數(shù)組中。
  • 移動(dòng)窗口,判斷當(dāng)前窗口前的元素是否和隊(duì)頭元素相等,如果相等則出隊(duì)。
  • 繼續(xù)然后按照規(guī)則進(jìn)行入隊(duì),維護(hù)單調(diào)遞減隊(duì)列。
  • 每次將隊(duì)頭元素存到返回?cái)?shù)組里。
  • 返回?cái)?shù)組
  • 是不是懂啦,再回去看一遍視頻吧。祝大家新年快樂,天天開心呀!

    上段文字來源:https://leetcode-cn.com/problems/sliding-window-maximum/solution/zhe-hui-yi-miao-dong-bu-liao-liao-de-hua-7fy5/

    class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int[] res = new int[nums.length-k+1];Deque<Integer> dq = new LinkedList<Integer>();//先將第一個(gè)窗口的元素按單調(diào)遞減規(guī)則存如雙端隊(duì)列中;for(int i=0; i<k; i++){while(!dq.isEmpty() && nums[i]>dq.peekLast())dq.removeLast();dq.offerLast(nums[i]);}res[0]=dq.peekFirst();//移動(dòng)窗口for(int i=1; i< nums.length-k+1; i++){//雙端隊(duì)列的頭元素已經(jīng)不在當(dāng)前窗口中if(dq.peekFirst()==nums[i-1])dq.removeFirst();//維護(hù)單調(diào)遞減隊(duì)列while(!dq.isEmpty() && nums[i+k-1]>dq.peekLast())dq.removeLast();dq.offerLast(nums[i+k-1]);res[i]=dq.peekFirst();}return res;} }

    ?

    總結(jié)

    以上是生活随笔為你收集整理的滑动窗口—最值问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。