题意:给定一串数字,一个定长的窗口,窗口每次平移一个位置,输出窗口中的最大值。
题解:
#include <cstdio> #define M 1000005 int n, k; struct min_Heap { int array[M], pos[M], id[M]; // id[i]表示堆内第i个元素对应的数组下标,pos[i]表示数组第i个元素在堆内的位置。 void siftDown ( int start ) //下滑调整,若子女的值小于父节点的值,则父节点上浮,之后继续向下层比较 { int i = start, j = i * 2 + 1; int temp = array[start]; while ( j < k ) { if ( j < k-1 && array[j] > array[j+1] ) ++j; if ( temp <= array[j] ) break; else { exch( i, j ); i = j; j = j * 2 + 1; } } } void siftUp ( int start ) //上滑调整,若子女的值小于父节点的值则互相交换 { int j = start, i = ( j - 1 ) / 2; int temp = array[j]; while ( j > 0 ) { if ( temp >= array[i] ) break; else { exch ( j, i ); j = i; i = ( i - 1 ) / 2; } } } void build_minHeap () //建堆 { int current = ( k - 2 ) / 2; while ( current >= 0 ) { siftDown ( current ); current--; } } void exch ( int x, int y ) { int temp; pos[id[x]] = y; pos[id[y]] = x; temp = id[x]; id[x] = id[y]; id[y] = temp; temp = array[x]; array[x] = array[y]; array[y] = temp; } } minHeap; struct max_Heap { int array[M], pos[M], id[M]; void siftDown ( int start ) { int i = start, j = i * 2 + 1; int temp = array[start]; while ( j < k ) { if ( j < k-1 && array[j] < array[j+1] ) ++j; if ( temp >= array[j] ) break; else { exch( i, j ); i = j; j = j * 2 + 1; } } } void siftUp ( int start ) { int j = start, i = ( j - 1 ) / 2; int temp =array[j]; while ( j > 0 ) { if ( temp <= array[i] ) break; else { exch( j, i ); j = i; i = ( i - 1 ) / 2; } } } void build_maxHeap () { int current = ( k - 2 ) / 2; while ( current >= 0 ) { siftDown ( current ); current--; } } void exch ( int x, int y ) { int temp; pos[id[x]] = y; pos[id[y]] = x; temp = id[x]; id[x] = id[y]; id[y] = temp; temp = array[x]; array[x] = array[y]; array[y] = temp; } } maxHeap; int main() { int i, t; scanf("%d%d",&n,&k); for ( i = 0; i < n; ++i ) { scanf("%d", &minHeap.array[i]); maxHeap.array[i] = minHeap.array[i]; minHeap.pos[i] = minHeap.id[i] = i; maxHeap.pos[i] = maxHeap.id[i] =i; } minHeap.build_minHeap (); printf("%d ", minHeap.array[0] ); for ( i = k; i < n; ++i ) { t = minHeap.pos[i-k]; minHeap.exch( i, t ); minHeap.siftUp ( t ); minHeap.siftDown ( t ); printf("%d ", minHeap.array[0] ); } putchar('\n'); maxHeap.build_maxHeap(); printf("%d ", maxHeap.array[0] ); for ( i = k; i < n; ++i ) { t = maxHeap.pos[i-k]; maxHeap.exch( i, t ); maxHeap.siftUp ( t ); maxHeap.siftDown ( t ); printf("%d ", maxHeap.array[0] ); } putchar('\n'); return 0; }
下面是单调队列的解法。 基本仿照http://blog.chinaunix.net/space.php?uid=22753395&do=blog&cuid=2208489的写法
#include <iostream> using namespace std; const int M = 1000005; int a[M], que[M], Min[M], Max[M], id[M]; int n, k; void get_min() { int i, head = 1, tail = 0; for ( i = 1; i < k; ++i ) { while ( head <= tail && que[tail] > a[i] ) --tail; ++tail; que[tail] = a[i]; id[tail] = i; } for ( i = k; i <= n; ++i ) { while ( head <= tail && que[tail] > a[i] ) --tail; ++tail; que[tail] = a[i]; id[tail] = i; while ( id[head] <= i-k ) ++head; Min[i-k] = que[head]; } } void get_max () { int i, head = 1, tail = 0; for ( i = 1; i < k; ++i ) { while ( head <= tail && que[tail] < a[i] ) --tail; ++tail; que[tail] = a[i]; id[tail] = i; } for ( i = k; i <= n; ++i ) { while ( head <= tail && que[tail] < a[i] ) --tail; ++tail; que[tail] = a[i]; id[tail] = i; while ( id[head] <= i-k ) ++head; Max[i-k] = que[head]; } } int main() { int i; scanf("%d%d", &n, &k ); for ( i = 1; i <= n; ++i ) scanf("%d",a+i); get_min(); get_max(); for ( i = 0; i < n-k+1; ++i ) printf("%d ", Min[i] ); putchar('\n'); for ( i = 0; i < n-k+1; ++i ) printf("%d ", Max[i] ); putchar('\n'); return 0; }