生成窗口最大值數組
【題目】?
有一個整型數組arr和一個大小為w的窗口從數組的最左邊滑到最右邊,窗口每次向右邊滑一個位置。?
例如,數組為[4,3,5,4,3,3,6,7],窗口大小為3時:?
?[4,3,5],4,3,3,6,7 窗口最大值:5
4,[3,5,4],3,3,6,7? 窗口最大值:5
4,3,[5,4,3],3,6,7?? 窗口最大值:5
4,3,5,[4,3,3],6,7? 窗口最大值:4
4,3,5,4,[3,3,6],7? 窗口最大值:6
? 4,3,5,4,3,[3,6,7]? 窗口最大值:7
如果數組長度為n,窗口大小為w,則一共產生n-w+1個窗口的最大值。?
請實現一個函數。?
(1)輸入:整型數組arr,窗口大小為:w。?
(2)輸出:一個長度為n-w+1的數組res,res[i]表示每一種窗口狀態下的最大值。
以本題為例,結果應該返回{5,5,5,4,6,7}。
【解答】
設數組的長度為N,窗口大小為w,剛開始我想的是挨個比較窗口內的值,找到其中的最大值進行存儲,然後再遍歷窗口在整個數組的移動過程,雖然也可以解出答案,但是時間復雜度為O(N*w)
,明顯這不是最佳答案。
題目要求找出當窗口在移動過程中可以找出每一個移動時刻時窗口內的最大值。所以,本題的關鍵在於利用雙端隊列來實現窗口最大值的更新。(註:雙端隊列是指允許兩端都可以進行入隊和出隊操作的隊列,其元素的邏輯結構仍是線性結構。將隊列的兩端分別稱為前端和後端,兩端都可以入隊和出隊。)
首先生成雙端隊列qmax,qmax中存放數組arr中的下標。
假設遍歷到arr[i],qmax的放入規則為:
*1.如果qmax為空,直接把下標i放進qmax,放入過程結束。
2.如果qmax不為空,取出當前qmax隊尾存放的下標,假設為j。
(1)如果arr[j]>arr[i],直接把下標i放進qmax的隊尾,放入過程結束。
(2)如果arr[j]<=arr[i],把j從qmax中彈出,繼續qmax的放入規則。
假設便利到arr[i],qmax的彈出規則為:
如果qmax隊頭的下標等於i-w,說明當前qmax隊頭的下標已經過期,彈出當前隊頭的下標即可。
根據以上的放入和彈出規則,qmax便成了一個維護窗口為w的子數組的最大值更新的結構。
【代碼實現】
GetMaxWindow.java:
1 package cn.hl.p5; 2 3 import java.util.LinkedList; 4 /** 5 * 生成窗口最大數值組 6 * 7 * 思想:題目要求找出當窗口在移動過程中可以找出每一個移動時刻時窗口內的最大值。 8 * 所以,本題的關鍵在於利用雙端隊列來實現窗口最大值的更新。 9 * (註:雙端隊列是指允許兩端都可以進行入隊和出隊操作的隊列, 10 * 其元素的邏輯結構仍是線性結構。將隊列的兩端分別稱為前端和後端,兩端都可以入隊和出隊。) 11 首先生成雙端隊列qmax,qmax中存放數組arr中的下標。 12 假設遍歷到arr[i],qmax的放入規則為: 13 1.如果qmax為空,直接把下標i放進qmax,放入過程結束。 14 2.如果qmax不為空,取出當前qmax隊尾存放的下標,假設為j。 15 (1)如果arr[j]>arr[i],直接把下標i放進qmax的隊尾,放入過程結束。 16 (2)如果arr[j]<=arr[i],把j從qmax中彈出,繼續qmax的放入規則。 17 假設便利到arr[i],qmax的彈出規則為: 18 如果qmax隊頭的下標等於i-w,說明當前qmax隊頭的下標已經過期,彈出當前隊頭的下標即可。 19 根據以上的放入和彈出規則,qmax便成了一個維護窗口為w的子數組的最大值更新的結構。 20 * 21 * @author 猩生柯北 22 * 23 */ 24 public class GetMaxWindow { 25 public int[] getMaxWindow(int[] arr, int w) { 26 if (arr == null || arr.length < w || w < 1) { 27 return null; 28 } 29 LinkedList<Integer> qmax = new LinkedList<Integer>(); 30 int[] res = new int[arr.length - w + 1]; 31 int index =0; 32 for (int i = 0; i < arr.length; i++) { 33 while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[i]) { 34 qmax.pollLast(); 35 } 36 qmax.addLast(i); 37 if (qmax.peekFirst() == i - w) { 38 qmax.pollFirst(); 39 } 40 if (i >= w -1 ) { 41 res[index++] = arr[qmax.peekFirst()]; 42 } 43 } 44 return res; 45 } 46 }
TestGetMaxWindow.java:
1 package cn.hl.p5; 2 //測試 3 public class TestGetMaxWindow { 4 public static void main(String[] args) { 5 GetMaxWindow gt = new GetMaxWindow(); 6 int[] a = {4,3,5,4,3,3,6,7}; 7 int w = 3; 8 int[] result = gt.getMaxWindow(a, w); 9 for(int i:result){ 10 System.out.println(i); 11 } 12 } 13 }
【運行結果】
生成窗口最大值數組