码迷,mamicode.com
首页 > 编程语言 > 详细

剑指offer——面试题29:数组中出现次数超过一半的数

时间:2015-08-27 16:40:58      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:

题目描述:

  数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

  例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

输入:

  每个测试案例包括2行:

  第一行输入一个整数n(1<=n<=100000),表示数组中元素的个数。

  第二行输入n个整数,表示数组中的每个元素,这n个整数的范围是[1,1000000000]。

输出:

  对应每个测试案例,输出出现的次数超过数组长度的一半的数,如果没有输出-1。

解法一:基于快排中分割算法的方法

  数组中有一个数字出现的次数超过了数组长度的一半。如果把这个数组排序,那么排序之后位于数组中间的数字一定就是那个出现次数超过数组长度一半的数字。

  也就是说,这个数字是统计学上的中位数,即长度为n的数组中第n/2大的数字。我们有成熟的O(n)算法得到数组中任意第k大的数字。

  这种算法是受快速排序算法的启发,在随机快排中,先随机选择一个数字,然后将比它小的数字都放在它的左边,比它大的都放在它的右边。

  如果调整好位置后,这个选中的数字的下标刚好是n/2,那么这个数字就是数组中的中位数。

  如果它的下标大于n/2,那么中位数应该在它的左边,可以接着在它的左边查找;下标小于n/2的情况类似,这是一个典型的递归过程。

  当然,在这其中要考虑输入无效的情况(数组指针为NULL);也要考虑如果输入的数组中出现频率最高的数字并没有达到出现次数超过数组长度一半的情况。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;

void change(int numbers[],int i,int j)
{
	int temp=numbers[i];
	numbers[i]=numbers[j];
	numbers[j]=temp;
}

int partion(int numbers[],int length,int start,int end)
{
	if(start==end)
		return start;
	int temp=numbers[end];
	int i=start;
	int j=end;
	while(i<j)
	{
		while(i<j&&numbers[i]<=temp)
			i++;
		change(numbers,i,j);
		while(i<j&&numbers[j]>=temp)
			j--;
		change(numbers,i,j);
	}
	return i;
}

int morethanhalf(int numbers[],int length)
{
	int start=0;
	int end=length-1;
	int mid=(length-1)/2;
	int index=partion(numbers,length,start,end);
	while(index!=mid)
	{
		if(index<mid)
		{
			start=index+1;
			end=end;
			index=partion(numbers,length,start,end);
		}
		else
		{
			start=start;
			end=index-1;
			index=partion(numbers,length,start,end);
		}
	}
	return numbers[index];
}

bool ifright(int numbers[],int length,int re)
{
	int times=0;
	for(int i=0;i<length;i++)
		if(numbers[i]==re)
			times++;
	if(times>=(length/2))
		return 1;
	else
		return 0;
}

  

解法二:根据数组特点找出O(n)的算法

  数组中有一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现的次数的和还要多

  因此我们可以考虑用两个变量:一个保存一个数字,一个保存次数。

  开始时,保存数组中第一个元素,次数设置为1;

  遍历数组:

  如果下一个数字和之前保存的数字相同,则次数递增1;

  如果下一个数字和之前保存的数字不同,则次数递减1;

  如果次数为零,我们需要保存下一个数字,并把次数设为1。

  由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。

  但是最后还是需要检查一下该数字的出现次数是否超过了数组长度的一半,因为可能数组中并不包含这样的数字。

int morethanhalf2(int numbers[],int length)
{
	int re=numbers[0];
	int num=1;
	for(int i=1;i<length;i++)
	{
		if(num==0)
		{
			re=numbers[i];
			num++;
		}
		else
		{
			if(re==numbers[i])
				num++;
			else
				num--;
		}
	}
	return re;
}

int main()
{
	int ary[5]={1,2,2,1,1};
	cout<<morethanhalf(ary,5)<<endl;

	//cout<<partion(ary,4,0,3)<<endl;
	system("pause");
}

  

剑指offer——面试题29:数组中出现次数超过一半的数

标签:

原文地址:http://www.cnblogs.com/yanliang12138/p/4763743.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!