Description
給定n個數,在最壞情況下用 3n/2-2 次比較找出這n個數中元素的最大值和最小值。
要求只編寫函數
void maxmin(int a[],int low,int high,int *max,int *min).
系統會自動在程序的最后加上如下代碼:
int main() { int max,min,k,a[200]; int m; while(scanf("%d",&k)&&k) { for(m=0;m<k;m++) scanf("%d",&a[m]); maxmin(a,0,k-1,&max,&min); printf("%d %d\n",max,min); } }
Input
包含多組測試數據。每組測試數據的第一個元素是整數的個數n,接下來是n個整數。0表示結束。 n<=200
Output
這n個數中的最大值和最小值。
Sample Input
5 1 8 2 4 3 3 2 4 1 0
Sample Output
8 1 4 1
如果之前遍歷一遍需要比較n-1次,才能得到數組中的最大值和最小值,這顯然是不符合預期要求的,這里應該采用的是分治思想。
分治法主要有三個步驟:
1.分解:將原問題划分為規模較小的幾個子問題。
2.求解:子問題小到可以求解了,就去求解。
3.合並:將子問題的解合並為原問題的解。
對於本問題就是不斷地進行二分,直到分解為不可分的一個數組元素,這個數組元素是最小子問題的最大值也是最小值,之后再逐一合並為原問題的解。
#include<cstdio> #include<algorithm> #define inf 0x3f3f3f3f using namespace std; void maxmin(int *a,int left,int right,int *max,int *min) { int mid; int lmax=0,lmin=inf,rmax=0,rmin=inf; if(left==right) { *max=a[left]; *min=a[right]; return ; } mid=(left+right)/2; maxmin(a,left,mid,&lmax,&lmin); maxmin(a,mid+1,right,&rmax,&rmin); if(lmax>rmax) { *max=lmax; } else { *max=rmax; } if(lmin<rmin) { *min=lmin; } else { *min=rmin; } return ; } int main() { int max,min,k,a[200]; int m; while(scanf("%d",&k)&&k) { for(m=0; m<k; m++) scanf("%d",&a[m]); maxmin(a,0,k-1,&max,&min); printf("%d %d\n",max,min); } }
使用分治法解決了本問題,但是3n/2-2 次比較是怎么計算得到的呢?
我們來分析一下本算法:
void maxmin(int *a,int left,int right,int *max,int *min) { int mid; int lmax=0,lmin=inf,rmax=0,rmin=inf; if(left==right) { *max=a[left]; *min=a[right]; return ; }// ------------------------------------------------>O(1) mid=(left+right)/2;//------------------------------->O(1) maxmin(a,left,mid,&lmax,&lmin);//------------------->T(n/2) maxmin(a,mid+1,right,&rmax,&rmin);//---------------->T(n/2) if(lmax>rmax) { *max=lmax; } else { *max=rmax; } if(lmin<rmin) { *min=lmin; } else { *min=rmin; } return ;//------------------------------------------>O(1) }
可以得到算法的遞推表達式,進而求解。