剑指offer第39题数组中出现超过一半的数字

题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如:输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。
          由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解法1:基于Partition函数的时间复杂度为O(n)的算法
思路:在排序后因为数组中有一个数字超过长度的一半,也就是说这个数字就是统计学上的中位数,即长度为n的数组中第n/2大的数字。
          随机快速排序

#include<iostream>
using namespace std;

bool g_bInputInvaild=false;
//检查输入的有效性 
bool CheckInValidArray(int* numbers,int length){
	g_bInputInvaild=false;
	if(numbers==nullptr||length<=0)
		g_bInPutInvalid=true;
		
	return g_bInPutInvalid;
}

//检查输入数组中出现频率最高的数字是否达到了这个标准

bool CheckMoreThanHalf(int*numbers,int length,int number){
	int times=0;
	for(int i=0;i<length;i++){
		if(numbers[i]==number)
			times++;
	}
	bool isMoreThanHalf=true;
	if(times*2<=length){
		g_bInPutInvalid=true;
		isMoreThanHalf=false;
	}
	return isMoreThanHalf;
} 

int Partition(int data[],int length,int start,int end){
	if(data==nullptr||length<=0||start<0||end>=length)
		throw new srd::exception("Invalid Parameters");
	
	int index=RandomInRange(start,end);
	Swap(&data[index],&data[end]);
	
	int small=start-1;
	for(index=start;index<end;++index){
		if(data[index]<data[end]){
			++small;
			if(small!=index)
				Swap(&data[index],&data[small]);
		}
	}
	++small;
	Swap(&data[small],&data[end]);
	
	return small;
} 

int MoreThanHalfNum(int *numbers,int length){
	if(CheckInvalidArray(numbers,length))
		return 0;
	
	int middle=length>>1;
	int start=0;
	int end=length-1;
	int index=Partition(numbers,length,start,end);
	while(index!=middle){
		if(index>middle){
			end=index-1;
			index=Partition(numbers,length,start,end);
		}
		else{
			start=index+1;
			index=Partition(numbers,length,start,end);
		}
	}
	int result=numbers[middle];
	if(!CheckMoreThanHalf(numbers,length,result))
		result=0;
	return result;
}

 

解法2:根据数组特点找出时间复杂度为O(n)的算法
思路: 我们可以考虑在遍历数组时候保存两个值:一个是数组中的一个数字;另一个是次数
           当我们遍历到下一个数字的时候:1.如果下一个数字和我们之前保存的数字相同,则次数加1
                         2.如果下一个数字和我们之前保存的数字不相同,则次数减1
                         3.如果次数为0,那么我们要保存下一个数字,并把次数设置为1
  结果:由于要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字一定是times大于等于1的时候那个结果

#include<iostream>
using namespace std;

bool g_bInputInvaild=false;
//检查输入的有效性 
bool CheckInValidArray(int* numbers,int length){
	g_bInputInvaild=false;
	if(numbers==nullptr||length<=0)
		g_bInPutInvalid=true;
		
	return g_bInPutInvalid;
}

//检查输入数组中出现频率最高的数字是否达到了这个标准

bool CheckMoreThanHalf(int*numbers,int length,int number){
	int times=0;
	for(int i=0;i<length;i++){
		if(numbers[i]==number)
			times++;
	}
	bool isMoreThanHalf=true;
	if(times*2<=length){
		g_bInPutInvalid=true;
		isMoreThanHalf=false;
	}
	return isMoreThanHalf;
} 

int MoreThanHalfNum(int *numbers,int length){
	if(CheckInValidArray(numbers,length))
		return 0;
	int result=numbers[0];
	int times=1;
	//
	for(int i=1;i<length;i++){
		//如果次数等于0的时候  保存后一个数字 
		//要找的数字肯定是result里保存的数字 
		if(times==0){
			result=numbers[i];
			times=1;
		}
		//如果下一个数字和之前保存的数字相同,次数加1 
		else if(numbers[i]==result)
			times++;
		//如果下一个数字和之前保存的数字不同,次数减一 
		else
			times--;
	}
	if(!CheckMoreThanHalf(numbers,length,result))
		result=0;
	return result;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值