題目描述
-
計算生成窗口最大值數組
-
有一個整型數組arr和一個大小爲w的窗口從數組最左邊滑到最右邊。
-
現在要求實現一個函數,輸入整型數組arr和窗口長度w,輸出一個最大值數組res記錄每個窗口的最大值。
解題方法1
- 最簡單粗暴的方法就是直接兩層遍歷,代碼如下。但是時間複雜度爲 n*w 顯然有優化的空間。
public class Test {
public static void main(String[] args) {
int [] arr = {4,3,5,4,3,3,6,7};
int [] res = fun(arr,3);
for(int a:res){
System.out.print(a+" ");
}
}
//計算每個窗口最大值並保存到數組返回
public static int [] fun(int [] arr,int w){
int [] res = new int[arr.length-w+1];
for(int i=0;i<arr.length-w+1;i++){
res[i] = getmax(arr,i,w);
}
return res;
}
//尋找一個窗口最大值
public static int getmax(int [] arr,int start,int w){
int max = arr[start];
for(int i=start+1;i<start+w;i++){
if(arr[i]>max){
max = arr[i];
}
}
return max;
}
}
解題方法2
- 可以使用雙端隊列進行優化,隊列中存放元素的下標。
- 隊頭彈出過期的下標,隊尾壓入值更小或等的下標,彈出值更大的下標。
- 這樣可以保證隊頭元素指向的永遠是當前窗口最大值。
- 我們根據arr數組當前遍歷位置i往前推w個元素便可以判斷隊頭是否還在窗口範圍內(是否過期)。
- 代碼如下:
public class Test {
public static void main(String[] args) {
int [] arr = {4,3,5,4,3,3,6,7};
int [] res = fun(arr,2);
for(int a:res){
System.out.print(a+" ");
}
}
//計算每個窗口最大值並保存到數組返回
public static int [] fun(int [] arr,int w){
int [] res = new int[arr.length-w+1];
LinkedList<Integer> queue = new LinkedList<>();
int index = 0; //index指向res數組的下標
for(int i=0;i<arr.length;i++){
//隊列爲空 或者 i指向元素<當前隊尾 將i壓入隊尾
if(queue.size()==0 || arr[i]<queue.peekLast()){
queue.addLast(i);
}
//否則 彈出當前隊尾繼續比較 直到當前i指向值<隊尾或者隊列爲空 然後再將i壓入隊尾
else{
while(queue.size()>0 && arr[i]>=arr[queue.peekLast()]){
queue.pollLast();
}
queue.addLast(i);
}
//如果當前隊頭過期了 就把隊頭出隊
if(queue.peekFirst()<(i-w+1)){
queue.pollFirst();
}
//如果當前可以構成一個窗口了 就將隊頭保存到數組res
if((i-w+1)>=0){
res[index] = arr[queue.peekFirst()];
index++;
}
}
return res;
}
}