寻找第k大的数:
第k大:(partition,基准值左边是小于他的数右边是大于他的数)
代码:
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
int n,k;
const int maxn=100010;
int a[maxn];
int partition(int a[],int left,int right){//找基准值,分成两部分;
int num=rand()%(right-left+1)+left;
int temp=a[num];
swap(a[num],a[left]);
while(left<right){
while(left<right&&temp<a[right])right--;
a[left]=a[right];
while(left<right&&a[left]<=temp)left++;
a[right]=a[left];
}
a[left]=temp;
return left;
}
void randselect(int a[],int left,int right,int k){
if(left==right)return ;//边界,找到第k大的数;
int p=partition(a,left,right);//基准值的下标;
int m=p-left+1;//基准值是数列里面的第m大的数;
if(m==k)return ;//如果刚好是基准值;
if(k<m){
randselect(a,left,p-1,k);//在左区间找;
}else {
randselect(a,p+1,right,k-m);//在右区间的一个新数列找,新数列的开始是p+1,所以是k-m,即是新数列的第k-m大的数,而不是第k大的数;
}
}
int main(){
srand((unsigned)time(NULL));
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
cin>>k;
randselect(a,0,n-1,k);
cout<<a[k-1];
return 0;
}
思路:利用基准值把区间分为两部分,大于它的数和小于它的数,用partition可以得到基准值的下标,下标-左边界+1就是在这个区间内,基准值是第(p-left+1)大,如果k(第k大)大于基准值的第(p-left+1)大,令m=p-left+1,就说明k在右区间,就让又区间作为一个左边界为p+1,右边界为right,因为区间改变,所以找的值是k-m不是k,k是原来区间的第k大,新区间的第k大应该是k-m,如果k<m,就说明在左区间,左区间和原区间的起点相同且k<m,所以就是k就不是k-m;
问题二:
一个数列里面,将这个数列尽可能的分成两个相等的部分,且满足两个数列的和的差最大,求这个差
思路:只用求出第n/2大,左边都是小于n/2大的数,右边都是大于n/2的数,不在意顺序,因为是求和,就可以算出前n/2的和s1,后s2,此时s2-s1最大;
代码:
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
int n,k;
const int maxn=100010;
int a[maxn];
int partition(int a[],int left,int right){//找基准值,分成两部分;
int num=rand()%(right-left+1)+left;
int temp=a[num];
swap(a[num],a[left]);
while(left<right){
while(left<right&&temp<a[right])right--;
a[left]=a[right];
while(left<right&&a[left]<=temp)left++;
a[right]=a[left];
}
a[left]=temp;
return left;
}
void randselect(int a[],int left,int right,int k){
if(left==right)return ;//边界,找到第k大的数;
int p=partition(a,left,right);//基准值的下标;
int m=p-left+1;//基准值是数列里面的第m大的数;
if(m==k)return ;//如果刚好是基准值;
if(k<m){
randselect(a,left,p-1,k);//在左区间找;
}else {
randselect(a,p+1,right,k-m);//在右区间的一个新数列找,新数列的开始是p+1,所以是k-m,即是新数列的第k-m大的数,而不是第k大的数;
}
}
int main(){
srand((unsigned)time(NULL));
int sum1=0;int sum2=0;int sum=0;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
sum+=a[i];
}
randselect(a,0,n-1,n/2);
for(int i=0;i<n/2;i++)sum1+=a[i];
sum2=sum-sum1;
cout<<sum2-sum1;
return 0;
}