【演算法實戰】生成視窗最大值陣列
本文字數:2000字
閱讀本文大概需要:5 分鐘
做演算法題了,題的難度我們分為“士,尉,校,將”四個等級。這個演算法題的模組是篇幅比較小的那種模組。首先是給出一道題的描述,之後我會用我的想法來做這道題,今天算是演算法題的第一道題,先來試試水。
問題描述(等級:尉)
有一個整型陣列arr和一個大小為w的視窗從陣列的最左邊滑到最右邊,視窗每次向右邊滑一個位置。
例如,陣列為[4,3,1,5,4,3,7,5],視窗大小為5時:
[4 3 1 5 4] 3 7 5 max = 5
4 [3 1 5 4 3] 7 5 max = 5
4 3 [1 5 4 3 7] 5 max = 7
4 3 1 [5 4 3 7 5] max = 7
即視窗最大值陣列為 result = {5, 5,7,7}
解答:
對於一道題,我一般會第一時間想到用暴力的方法來做,之後再來慢慢最佳化。
顯然,對於這道題用暴力法來做還是挺簡單了,視窗每次向右移動一位時,我們每次遍歷視窗內的w個元素,然後求出此時視窗的最大值就可以了,用這種方法的時間複雜度是 O(wn)。程式碼如下:
//暴力法求解
public static int[] getMaxWindow(int[] arr, int w) {
if (w < 1 || arr == null || arr.length < w) {
return null;
}
int[] result = new int[arr.length - w + 1];
int index = 0;
//暴力求解直接從第 w-1個元素開始遍歷
for (int i = w - 1; i < arr.length; i++) {
int max = arr[i];
//找出最大值
for (int k = i; k > i - w; k--) {
if (max < arr[k]) {
max = arr[k];
}
}
result[index++] = max;
}
return result;
}
注:可以左右拉動
大家想一個問題,例如對於剛才例題中的陣列:
第一次遍歷的時候,max = 5
第二次遍歷的時候,max = 5
我們剛才用暴力法的時候,無論是第一次還是第二次,我們都是把視窗內的所有元素都給遍歷了一次,以此來尋找最大值,可是,真的需要這樣嗎?
第一次遍歷的時候,我們找出了max = 5, 那麼在第二次遍歷的時候,在視窗範圍內,max = 5 左邊的兩個數1, 3 還有可能是最大值嗎?也就是說,max=5 左邊的視窗元素還要必要遍歷嗎?
顯然,max=5左邊的視窗實際上是不必再遍歷的了,也就是它不可能會是視窗的最大值。
而 max = 5 右邊的 4 有可能會是視窗的最大值嗎?由於視窗還會一直向右移動,所以 max = 5 右邊的視窗元素還是有可能是某一個視窗的最大值的。
因此,我們可以用一個雙向的佇列,來記錄有可能成為視窗最大值的下標,注意,這裡指的是有可能。
像剛才的 max = 5 前面的 1,3 就不可能成為視窗的最大值了,而右邊的4還是有可能成為視窗的最大值的。並且這個佇列是有序的,隊首存放的總是佇列中的最大值,
我以這道題來演示一下,我們用result[] 陣列來存放視窗最大值。
1、result[0] = 5
2、result[1] = 5;
3、result[2] = 7
其他的全部都要出隊,因為7前面的5,4,3是不可能成為視窗最大值的了。
4、result[3] = 7
遍歷完畢。這種方法的話時間複雜度是 O(n)。
我這裡只是提供了思路與大致的做法,具體的程式碼實現還是有很多細節需要注意的。下面給出實現程式碼,程式碼會有詳細的解釋。
//最佳化
public static int[] getMaxWindow2(int[] arr, int w) {
if (w < 1 || arr == null || arr.length < w) {
return null;
}
//用來儲存成為最大視窗的元素
int[] result = new int[arr.length - w + 1];
int index = 0;
//用連結串列從當雙向佇列。
LinkedList<Integer> temp = new LinkedList<>();
//剛才演示的時候,我i直接從i = w-1那裡開始演示了。
for (int i = 0; i < arr.length; i++) {
//如果佇列不為空,並且存放在隊尾的元素小於等於當前元素,那麼
//佇列的這個元素就可以彈出了,因為他不可能會是視窗最大值。
//【當前元素】指的是視窗向右移動的時候新加入的元素。
while (!temp.isEmpty() && arr[temp.peekLast()] <= arr[i]) {
temp.pollLast();//把隊尾元素彈出
}
//把【當前元素】的下邊加入到隊尾
temp.addLast(i);
//如果隊首的元素不在視窗範圍內,則彈出
if (temp.peekFirst() == i - w) {
temp.pollFirst();//
}
if (i >= w - 1) {
//由於隊首存放的是最大值,所以隊首總是對應視窗的最大值元素
result[index++] = arr[temp.peekFirst()];
}
}
return result;
}
說實話,微信看程式碼確實有點難受,如果是在電腦瀏覽的話還好點,我在考慮要不要用截圖的方式,不過如果是截圖的話,有些人想要複製程式碼的話會複製不了,那我之後考慮把程式碼打包,你們後臺回覆獲取。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31561266/viewspace-2286701/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 滑動視窗最大值——棧與佇列佇列
- 滑動視窗最大值的golang實現Golang
- 演算法題:返回滑動視窗中的最大值演算法
- [劍指offer題解][Java]佇列的最大值/滑動視窗的最大值Java佇列
- 滑動視窗的最大值
- 239. 滑動視窗最大值
- 滑動視窗最大值問題
- [Leetcode]雙項佇列解決滑動視窗最大值難題LeetCode佇列
- LeetCode 410——分割陣列的最大值LeetCode陣列
- JavaScript 獲取陣列中最大值JavaScript陣列
- JavaScript 陣列排序 與 求最大值JavaScript陣列排序
- LeetCode 239. 滑動視窗最大值LeetCode
- 滑動視窗的最大值問題
- [Python手撕]滑動視窗最大值Python
- 4-陣列-案例實戰陣列
- 鴻蒙HarmonyOS實戰-視窗管理鴻蒙
- JavaScript 陣列最大值和最小值JavaScript陣列
- JZ-064-滑動視窗的最大值
- 程式碼隨想錄陣列二刷:長度最小的子陣列(滑動視窗)陣列
- 陣列演算法-差分陣列陣列演算法
- 劍指offer(59)——滑動視窗的最大值
- 【程式碼隨想錄】一、陣列:4.滑動視窗陣列
- 程式碼隨想錄演算法訓練營第2天 | 陣列滑動視窗、螺旋列印演算法陣列
- JavaScript獲取陣列最大值和最小值JavaScript陣列
- JavaScript陣列中的最大值和最小值JavaScript陣列
- JavaScript陣列最大值、最小值和平均數JavaScript陣列
- 2439. 最小化陣列中的最大值陣列
- Python演算法與資料結構--求所有子陣列的和的最大值Python演算法資料結構陣列
- Python演算法與資料結構–求所有子陣列的和的最大值Python演算法資料結構陣列
- Leetcode 239. 滑動視窗最大值 (Java實現 超詳細註釋!)LeetCodeJava
- 演算法-陣列與矩陣演算法陣列矩陣
- 求陣列之和,最小值,最大值,平均值陣列
- Go語言實現時間滑動視窗演算法 動態計算增加量、最大值、最小值Go演算法
- Hive實戰—時間滑動視窗計算Hive
- 騰訊面試題-求滑動視窗的最大值面試題
- JavaScript split() 分割字串生成陣列JavaScript字串陣列
- 滑動視窗演算法演算法
- 演算法~利用zset實現滑動視窗限流演算法