2021-01-02 239 [Deque]
239. 滑動視窗最大值
思路一:(超時)
- 如果在最新的區間最右側值C,比上一個區間最左側的值A要大,則因為兩者共用區間中最大值B一定比A要小,所以如果C比A大,則新區間最大值一定是C。
- 否則,我們就從頭掃描這個區間得到最大值
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int l = nums.length;
int[] res = new int[l-k+1];
int tmp = nums[0]; //因為nums.length>=1
for(int i=1;i<k;i++) // k<=l
tmp = Math.max(tmp,nums[i]);
res[0]=tmp;
for(int i=1;i<l-k+1;i++){
// 如果最大值是在新的區間裡取到
if(nums[i+k-1]>=res[i-1])
res[i] = nums[i+k-1];
//否則,就是在找res[i,i+k-1]之中的最大值
else{
int tmp2 = nums[i];
for(int j=i+1;j<i+k;j++)
tmp2 = Math.max(tmp2,nums[j]);
res[i]=tmp2;
}
}
return res;
}
}
複雜度:
在最壞的情況下,即
A
>
C
A>C
A>C的情況下為
O
(
N
2
)
O(N^2)
O(N2)。
思路二:PriorityQueue(依舊超時)
在這裡我們可以引入一個單調佇列,每次保證它只有k個元素,這樣每次新增和刪除一個元素只要用 O ( l o g k ) O(logk) O(logk),一共進行 O ( n − k + 1 ) O(n-k+1) O(n−k+1)次操作,所以複雜度為 O ( n l o g k ) O(nlogk) O(nlogk)。
public int[] maxSlidingWindow(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>(k,new Comparator<Integer>() {
@Override
public int compare(Integer i1, Integer i2) {
return i2 - i1;
}
});
int l = nums.length;
int[] res = new int[l-k+1];
// 因為nums.length >= k
for(int i=0;i<k;i++)
pq.add(nums[i]);
res[0]=pq.peek();
for(int i=1;i<res.length;i++){
pq.remove(nums[i-1]);
pq.add(nums[i+k-1]);
res[i]=pq.peek();
}
return res;
}
思路三:用Deque實現的單調佇列
思路:
我們用一個雙向連結串列來儲存陣列中的下標,它滿足如下的性質:
- ∀ i ≤ j , n u m s [ i ] ≥ n u m s [ j ] \forall i\leq j, nums[i]\geq nums[j] ∀i≤j,nums[i]≥nums[j]
因此,我們每次找最大值的時候,對於當前視窗[L,R],只要找 m i n { i ∈ deque 使得 L ≤ i ≤ R } min\{i \in \text{deque 使得} L \leq i\leq R\} min{i∈deque 使得L≤i≤R}
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
Deque<Integer> deque = new LinkedList<Integer>();
// 初始化第一個視窗
for (int i = 0; i < k; ++i) {
// 如[6,5,3,2] 加 4,則這個while會把原來的dequeue變成[6,5]
// 注意如果相等的話,我們也要取新的大一點的下標
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
deque.pollLast();
}
deque.offerLast(i);
}
int[] ans = new int[n - k + 1];
ans[0] = nums[deque.peekFirst()];
for (int i = k; i < n; ++i) {
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
deque.pollLast();
}
deque.offerLast(i);
// 刪除多餘的元素,這裡的R=i,L=i-k+1 (出while迴圈下標i一定>i-k)
while (deque.peekFirst() <= i - k) {
deque.pollFirst();
}
ans[i - k + 1] = nums[deque.peekFirst()];
}
return ans;
}
}
Deque
// 初始化
Deque<Integer> deque = new LinkedList<Integer>();
// 新增元素 O(1)
deque.offerFirst(1);
deque.offerLast(2);
// 檢視一個元素 O(1)
deque.peekFirst();
deque.peekLast();
// 刪除一個元素 O(1)
System.out.println(deque.pollFirst());
System.out.println(deque.pollLast());
例子:
- 輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
- 輸出: [3,3,5,5,6,7]
- 初始狀態:L=R=0,佇列:{},其中L,R為當前視窗的下標。
i=0,nums[0]=1,佇列為空,直接加入。佇列:{0}
i=1,nums[1]=3,隊尾值為nums[0]=1<3,所以彈出隊尾值。佇列:{1}
i=2,nums[2]=-1,隊尾值為nums[1]=3>-1,直接加入,佇列:{1,2} 此時視窗形成 L=0,R=2,result=nums[1]=3
i=3,nums[3]=-3,隊尾值為nums[2]=-1>-3,直接加入,佇列:{1,2,3} 此時L=1,R=3,nums[1]有效,result=[3,3]
i=4,nums[4]=5,隊尾值為nums[3]=-3<5,依次彈出後加入,佇列:{4} 此時L=2,R=4,nums[4]有效,result=[3,3,5]
i=5,nums[5]=3,隊尾值為nums[4]=5>3,直接加入,佇列:{4,5},此時L=3,R=5,nums[4]有效,result=[3,3,5,5]
i=6,nums[6]=6,隊尾值為nums[5]=3<6,依次彈出後加入。佇列:{6},此時L=4,R=6,nums[5]有效,result=[3,3,5,5,6]
i=7,nums[7]=7,隊尾值為nums[6]=6<7,依次彈出後加入。佇列:{7},此時L=5,R=7,nums[7]有效,result=[3,3,5,5,6,7]
相關文章
- 2021-01-02
- deque
- STL————deque容器
- STL容器之deque
- STL_deque容器
- STL使用篇__deque
- STL-queue&deque&stack
- C++ STL deque容器C++
- [LeetCode] 641. Design Circular DequeLeetCode
- python deque的兩大優點Python
- 如何在Java中使用Deque? - Java67Java
- 239. 滑動視窗最大值
- LeetCode 239. 滑動視窗最大值LeetCode
- [20220105]sqlplus &1替換最大支援239個字元.txtSQL字元
- PostgreSQL 原始碼解讀(239)- Locks(OOM & max_locks_per_transaction#2)SQL原始碼OOM
- huawei0821筆試第二題筆記:雙端佇列deque筆試筆記佇列
- Python實用技法第2篇:使用deque保留最新的N個元素Python
- 征服Excel VBA:讓你工作效率倍增的239個實用技巧Excel
- 科技愛好者週刊(第 239 期):未來兩種人會增加
- C++ STL第三篇(搞清楚deque原理和有多少用法)C++
- Leetcode 239 滑動視窗最大值 與堆排序kotlin語言(超時)LeetCode排序Kotlin
- Leetcode 239. 滑動視窗最大值 (Java實現 超詳細註釋!)LeetCodeJava
- 聯合國糧農組織:2019年世界糧食安全和營養狀況報告(239頁)
- 零壹財經:2018年Q3問題P2P平臺239家 爭議平臺48家
- 程式碼隨想錄 第13天 | ● 239. 滑動視窗最大值 ● 347.前 K 個高頻元素 ● 總結
- 洛圖科技:2024年10月中國監控攝像頭線上市場銷量為239萬臺 同比增長9.1%
- Day10(棧與佇列) | 150. 逆波蘭表示式求值 239. 滑動視窗最大值 347.前 K 個高頻元素佇列
- 程式碼隨想錄刷題day 11 | **150. 逆波蘭表示式求值** **239. 滑動視窗最大值** **347.前 K 個高頻元素**
- 程式碼隨想錄演算法訓練營第23天(補第11天)|150. 逆波蘭表示式求值,239. 滑動視窗最大值演算法
- 程式碼隨想錄演算法訓練營day11|150. 逆波蘭表示式求值 239. 滑動視窗最大值 347.前 K 個高頻元素演算法
- 程式碼隨想錄演算法訓練營第十二天|150.逆波蘭表示式求值、239.滑動視窗最大值、347.前k個高頻元素演算法