滑動視窗(from openjudge)
在解決這個問題的時候,會碰到超時的問題。在資料量很大的情況下,不難想到需要用scanf和printf進行輸入輸出,但是即便是這樣也會導致超時,所以就需要在演算法上做出改變。這也就是這道題的重點:遞增/遞減佇列。
所謂遞增(遞減)佇列想要實現的就是佇列中的元素是有序排列的。在一開始我們會想要直接利用stl庫中的優先佇列實現這個事情,但是問題在於我們難以進入到優先佇列的中間進行操作,只能對頭和尾進行操作,在面對這個題裡面對於視窗長度的限制的時候很難完成任務,所以我們選擇自己實現乙個雙端佇列的遞增(遞減)佇列結構。
這個結構模擬乙個佇列,利用val儲存資料,front代表佇列頭,back代表佇列尾,在隊列為空的時候front=back。在這個佇列中最核心的操作就是push。push的作用是加入乙個新元素。在本題中,以隊頭元素最大的隊列為例,push需要實現如下的工作:首先,如果從隊頭開始的元素已經在視窗範圍之外,那麼就將其刪除(front+1);其次,如果從隊尾開始的元素小於我們現在要加入佇列的數,那麼將其出佇列(back-1)。
在處理的過程中,需要注意以下兩個問題:
1. 因為是對陣列中的數字操作,為了實現判斷數字是否在視窗之內,我們在佇列中儲存的是數字在陣列中的索引(具體可看**實現)
2. 注意在實現從隊首、隊尾操作過程中的邊界判斷(front)
**實現如下
#include
#include
#include
using namespace std;
const int n = 2000000;
int num[n/2]; /*儲存輸入資料*/
int ansup[n/2]; /*儲存視窗中的大元素答案*/
int ansdown[n/2]; /*儲存視窗中的小元素答案*/
//遞減佇列,找大元素
struct queueup
//x傳入的是在num中的索引
int push(int x)
int tmp = num[x];
//刪掉視窗外的元素
while (front < back && x - val[front] >= window)
front++;
//刪掉從末尾開始的小元素
while (back - 1 >= front && tmp >= num[val[back - 1]])
back--;
val[back] = x;
back++;
return val[front];
}};//遞增佇列,找小元素
struct queuedown
//x傳入的是在num中的索引
int push(int x)
int tmp = num[x];
while (front < back && x - val[front] >= window)
front++;
while (back - 1 >= front && tmp <= num[val[back - 1]])
back--;
val[back] = x;
back++;
return val[front];
}};int main()
int count = 0;
for (int i = k - 1; i < n; i++)
for (int i = 0; i < count; i++)
printf("%d ", num[ansdown[i]]);
cout << endl;
for (int i = 0; i < count; i++)
printf("%d ", num[ansup[i]]);
cout << endl;
return 0;
}至此完結~~
Leetcode 最小調整數 滑動視窗遞增子串行
給定乙個長度為n的陣列,以及乙個乘積值b,每次只能對乙個數增大或減少乙個單位,問最少多少次使得陣列乘積為b 思路 要使得調整的次數最少,那麼最開始調整的那個數字,應該是最小的數。貪心策略 選最小的數調整,其它部分數乘積最大 自己需要調整的偏移值就盡可能小 先對原先陣列從小到大排序。對於k 如果 b ...
Week5 D 滑動視窗滑動視窗
week5 d 滑動視窗滑動視窗 zjm 有乙個長度為 n 的數列和乙個大小為 k 的視窗,視窗可以在數列上來回移動.現在 zjm 想知道在視窗從左往右滑的時候,每次視窗內數的最大值和最小值分別是多少.例如 數列是 1 3 1 3 5 3 6 7 其中 k 等於 3.window position ...
week5 D 滑動視窗滑動視窗
zjm 有乙個長度為 n 的數列和乙個大小為 k 的視窗,視窗可以在數列上來回移動.現在 zjm 想知道在視窗從左往右滑的時候,每次視窗內數的最大值和最小值分別是多少.例如 數列是 1 3 1 3 5 3 6 7 其中 k 等於 3.window position minimum value max...