單調隊列

單調隊是通過維護隊列嚴格單調來解決問題,先看一個問題(北大OJ 2823):

分析一下問題:這是一個滑動窗口問題,題意是(英語菜雞的翻譯):

給你一個大小爲 n (n<=10^6)的數組,有一個大小爲k的滑動窗口從最左邊移動到最右邊,你只能看到窗口裏的k個數字,每次滑動窗口移動一個位置,下面是一個例子(如上圖)其中數組是[1 3 -1 -3 5 3 6 7],k 是 3你的任務是在滑動窗口的每一個位置確定最大值和最小值。

輸入

輸入包含兩行,第一行是2個整數 n 和 k 分別是數組和滑動窗口的長度,並在第二行打出數組的n個整數。

輸出
輸出兩行,第一行分別給出窗口從左到右每個位置的最小值,第二行給出最大值。

輸入樣例
8 3
1 3 -1 -3 5 3 6 7
輸出樣例
-1 -3 -3 -3 3 3
3  3  5  5  6  7

ok 那麼來分析一下如何求得每一個位置的最大值

比如拿樣例數組 [1 3 -1 -3 5 3 6 7] 來說 首先如果按照一般的想法來做是一段一段的通過遍歷來求每個滑動窗口的最大值,那複雜度是 O(n^2) 你看給的數組大小是在 10^6 之內的如果給的數據過大肯定會超時,那有沒有 O(n) 的算法呢?(明知故問),答案是肯定的,那就是拿一個隊列來存儲 上面那個數組 通過維護一個嚴格單調遞減的隊列 來尋找每個窗口的最大值,具體通過代碼來展示吧 :

獲取最大值的代碼:

void GetMax(int n,int k){
	int Head=0, Tail=0, i=0;
	queue1[Tail] = 0;
	for (i=0;i<n;i++){
		while (Head<=Tail&&array[queue1[Tail]]<=array[i]) Tail --;
		queue1[++Tail] = i;
		while (queue1[Tail]-queue1[Head] >= k) Head ++;
		if (i>=k-1)
		printf("%d ",array[queue1[Head]]);
	}
	printf("\n");
}

獲取最小值的代碼:

void GetMin(int n,int k){
	int Head=0, Tail=0, i=0;
	queue2[Tail] = 0;
	for (i=0;i<n;i++){
		while (Head<=Tail&&array[queue2[Tail]]>=array[i]) Tail --;
		queue2[++Tail] = i;
		while (queue2[Tail]-queue2[Head] >= k) Head ++;
		if (i>=k-1)
		printf("%d ",array[queue2[Head]]);
	}
	printf("\n");
}

剛剛去OJ提交了一波 編譯器用GCC超時,用的C編譯器Accept。

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