哪个数字超过了一半?
数组中有一个数字出现的次数,超出了数组长度的一般,找出这个数字。
解法1:排序后返回arr[N/2], Nlg(N)。
解法2:hash统计。
解法3:分区,进行顺序统计 ; 需要改动原来数组的内容 。
解法4: 不同的数,进行消除, O(N)。
#include <iostream>
#include<algorithm>
using namespace std;
int selectK(int A[],int p,int r,int k);
int partition(int A[],int p,int r);
//解法1:排序后返回arr[N/2], Nlg(N)
void solve1(int arr[],int length){
sort(arr,arr+length);
cout<<arr[length/2];
}
//解法2:hash统计
//解法3:分区,进行顺序统计 ; 需要改动原来数组的内容
void solve3(int arr[],int length){
int res=selectK(arr,0,length-1,length/2);
cout<<res;
}
//解法4: 不同的数,进行消除, O(N)
void solve4(int arr[],int length){
//候选数
int candidate=arr[0];
int nTime=1;
for(int i=1;i<length;i++){
//两两消减为0,应该把现在的元素作为候选值
if(nTime==0){
candidate=arr[i];
nTime=1;
continue;
}
//遇到和候选值相同的,次数+1
if(arr[i]==candidate){
nTime++;
}
else{
nTime--;
}
}
cout<<candidate;
}
int main()
{
int arr[]={0,1,2,1,1};
int len=5;
solve1(arr,len);
cout<<endl;
solve3(arr,len);
cout<<endl;
solve4(arr,len);
return 0;
}
int selectK(int A[],int p,int r,int k){
int q=partition(A,p,r); //主元下标
int qK=q-p+1; //主元是第几个元素(排好序后)
if(qK==k){
return A[q];
}
else if(qK>k){
return selectK(A,p,q-1,k);
}
else{
return selectK(A,q+1,r,k-qK);
}
}
//三点中值法
int partition(int A[],int p,int r){
//优化: 在p、r、mid之间,选一个中间值作为主元
int midIndex=p+((r-p)>>1); //中间下标
int midValueIndex=-1; //中值的下标
if(A[p]<=A[midIndex]&&A[p]>=A[r]){
midValueIndex=p;
}
else if(A[r]<=A[midIndex]&&A[r]>=A[p]){
midValueIndex=r;
}
else{
midValueIndex=midIndex;
}
swap(A[p],A[midValueIndex]);
int pivot=A[p];
int left=p+1;//扫描指针
int right=r; //右侧指针
while(left<=right){
//left不停往右走,直到遇到大于主元的元素
while(A[left]<=pivot) left++; //循环退出时,left一定是指向第一个大于主元的位置
while(A[right]>pivot) right--; //循环退出时,right一定是指向最后一个小于等于主元的位置
if(left<right){
swap(A[right],A[left]);
}
}
//while退出时,两者交错,且right指向的是最后一个小于等于主元的位置,也就是主元应该待的位置
swap(A[p],A[right]);
return right; //返回主元在交换完成后的下标
}