选择第n大的数(分治法和排列实现)
个人心得:在买的书上看到的一个经典分治题,题目意思就是给定一个数组,求第k小的数。
第一反应就是排序,然后返回第k-1位置的数就可以了,这样算法的复杂度是nlongn,在快速排序的基础下还是挺不错的。
不过为了学习分治法还是换种思路,这也是建立在快速排序的方法,因为快排是以第一个作为标准,比他小的数在左边,大的数在右边。
所以此时就有nleft表示左边的个数
1:如果nleft=k-1,那么此时flag必然是第k小的数
2:如果大于,那么就在左边找就好了,问题规模变小了
3:如果小于,去右边,不过此时选择k-nelft-1(解释,本代码自动跳跃flag这个数所以还要减去1)
注意问题的转移和基准的确定。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iomanip> 6 #include<algorithm> 7 using namespace std; 8 #define maxi 105 9 int a[maxi]; 10 int b[maxi]; 11 int n,k; 12 void geta(){ 13 for(int i=0;i<n;i++) 14 b[i]=a[i]; 15 } 16 int sorta(){ 17 sort(b,b+n); 18 return b[k-1]; 19 } 20 int quickcheck(int left,int right,int ki) 21 { 22 if(left>=right) return a[left]; 23 int i=left; 24 int j=right+1; 25 int flag=a[left]; 26 while(true){ 27 do 28 { 29 i++; 30 }while(a[i]<flag); 31 do 32 { 33 j--; 34 }while(a[j]>flag); 35 if(i>=j) break; 36 swap(a[i],a[j]); 37 } 38 int nleft=j-left; 39 if(nleft==ki-1) return flag; 40 a[left]=a[j]; 41 a[j]=flag; 42 if(nleft<ki-1) 43 return quickcheck(j+1,right,ki-nleft-1); 44 else 45 return quickcheck(left,j-1,ki); 46 } 47 48 int main() 49 { 50 cin>>n>>k; 51 for(int i=0;i<n;i++) cin>>a[i]; 52 geta(); 53 cout<<sorta()<<endl<<quickcheck(0,n-1,k)<<endl; 54 return 0; 55 }