[算法] - 窗口內最大值更新結構【重要】

目錄

1. 由一個代表題目, 引出一種結構

2. 窗口內最大值更新結構

3. 具體代碼

4. 上述程序中所學


1. 由一個代表題目, 引出一種結構


【 題目】
有一個整型數組arr和一個大小爲w的窗口從數組的最左邊滑到最右邊, 窗口每次 向右邊滑一個位置。例如, 數組爲[4,3,5,4,3,3,6,7], 窗口大小爲3時:
[4 3 5]4 3 3 6 7
4[3 5 4]3 3 6 7
4 3[5 4 3]3 6 7
4 3 5[4 3 3]6 7
4 3 5 4[3 3 6]7
4 3 5 4 3[3 6 7]
窗口中最大值爲5 窗口中最大值爲5 窗口中最大值爲5 窗口中最大值爲4 窗口中最大值爲6窗口中最大值爲7
如果數組長度爲n, 窗口大小爲w, 則一共產生n-w+1個窗口的最大值。
請實現一個函數。 輸入:整型數組arr, 窗口大小爲w。
輸出:一個長度爲n-w+1的數組res, res[i]表示每一種窗口狀態下的 以本題爲例, 結果應該
返回{5,5,5,4,6,7}。 

2. 窗口內最大值更新結構

顧名思義,就是指 一個移動的窗口範圍內的更新變動的最大值。

一個L,一個R,每次只能向右移動1.

核心是利用雙端隊列結構(R移動一種情況,L移動一種情況),內部存放數組arr的index位置信息。雙端隊列的頭節點就是當前窗口的最大值。

要求內部: 大————小 排列

  • R移動:如果不滿足就從尾部彈出數據,直到滿足爲止。
  • L移動:看此時,窗口長度是否超度W,如超過,視爲過期,從頭部彈出。

3. 具體代碼

import java.util.LinkedList;//LinkedList雙端鏈表

public class Code01_SlidingWindowMaxArray {

	public static int[] getMaxWindow(int[] arr, int w) {//w窗口大小
		if (arr == null || w < 1 || arr.length < w) {
			return null;
		}
		LinkedList<Integer> qmax = new LinkedList<Integer>();
		int[] res = new int[arr.length - w + 1];//總共收集的結果
		int index = 0;//res[index]寫入index
		for (int i = 0; i < arr.length; i++) {//i表示窗口R
			//準備存入i位置的arr[i]
			while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[i]) {
				qmax.pollLast();//從尾部彈出
			}
			qmax.addLast(i);//加入arr[i]到尾部
			if (qmax.peekFirst() == i - w) {//如果頭部已經要過期了  i - w表示過期的下標
				qmax.pollFirst();//如果已經到窗口極限了,彈出頭部,L開始右移動
			}
			if (i >= w - 1) {//當窗口已經形成了,記錄每一步的res
				res[index++] = arr[qmax.peekFirst()];
			}
		}
		return res;
	}

	// for test
	public static void printArray(int[] arr) {
		for (int i = 0; i != arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		int[] arr = { 4, 3, 5, 4, 3, 3, 6, 7 };
		int w = 3;
		printArray(getMaxWindow(arr, w));

	}

}

4. 上述程序中所學

  1. 從遍歷開始有了i,然後就不要想遍歷了,想的是在i處,可能的情況
  2. 以本章爲例,先用while處理,不滿足大——小結構的數據,其實就是在這裏體現了這個結構。
  3. 通過上面的處理,下面的就可以用直接的邏輯了。

for (int i = 0; i < arr.length; i++) {// i表示窗口R
            //準備存入i位置的arr[i]
            while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[i]) {
                qmax.pollLast();//從尾部彈出
            }
            qmax.addLast(i);//加入arr[i]到尾部
            if (qmax.peekFirst() == i - w) {//如果頭部已經要過期了  i - w表示過期的下標
                qmax.pollFirst();//如果已經到窗口極限了,彈出頭部,L開始右移動
            }
            if (i >= w - 1) {//當窗口已經形成了,記錄每一步的res
                res[index++] = arr[qmax.peekFirst()];
            }
        }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章