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

题目描述:

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

  例如输入一个长度为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");
}

  

时间: 2024-08-13 10:32:25

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

【剑指offer】Q29:数组中出现次数超过一半的数字

就本题而言,个人觉得练习下partition函数是有必要的,毕竟它是快速排序的核心,是基础性的东西,也是必须要掌握的,至于书中给出的"取巧"性解法,是属于个人思维能力的考察,是一种考虑问题的思路,不是一两个问题就能练就的. partition函数,包括快速排序,是一定要信手拈来的,必须的. import random def MoreThanHalf(array): if len(array) == 0: return 0 start = 0 end = len(array) - 1

剑指offer系列源码-数组中出现次数超过一半的数字

题目1370:数组中出现次数超过一半的数字 时间限制:1 秒内存限制:32 兆特殊判题:否提交:2844解决:846 题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. 输入: 每个测试案例包括2行: 第一行输入一个整数n(1<=n<=100000),表示数组中元素的个数. 第二行输入n个整数,表示数组中的每个元素,这n个整数的范围是[1,10

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

题目: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5此,超过数组长度的一半,因此输出2 分析: 因为是这个数出现的次数比其他数出现次数的总和还多,所以可以考虑用栈做,用来两两抵消. 如果碰到一样的,则加上,如果碰到与栈的末尾不一样,则弹出一个(抵消). 这样到了最后,剩下的栈的最后一个肯定还是那个超过半数的数字 代码: public int getNum(int[] array) { i

【剑指offer】39、数组中出现次数超过一半的数字

题目 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 思路一 基于partition,挑一个数字,把数组分成两部分,左边都比它小,右边都比它大. 因为有一个数字出现的次数超过长度的一半 因此当选中的数字的index = n/2,这个数字就是中位数 然后再检查它次数是否超过一半即可,时间复杂度为O(n) class Solution {

【剑指Offer】28、数组中出现次数超过一半的数字

题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 题解一:HashMap 1 public static int MoreThanHalfNum_Solution(int [] array) { 2 if (array.length == 0) { 3 return 0; 4 } 5 //分别存放重复的元素以及出现的次数 6

【剑指offer】Q40:数组中出现一次的数

书里面关于分类的判断有些麻烦,通过某一位为0为1来对数组元素进行分类.假如第3位为1,那么也就是元素x & 8 等于或不等于0,所以没必要非的用第几位去判断. def once(array): reOR = 0 for x in array: reOR ^= x bit1 = firstBit1(reOR) first = 0 second = 0 for x in array: if x & bit1 != 0: first ^= x else: second ^= x return f

剑指offer 面试题36—数组中的逆序对

题目: 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.例如在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4) 基本思想: 解法一:O(n^2) 最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是O(n^2). 解法二:O(nlogn) 归并排序思路: 例如7,5,4,6可以划分为两段7,5和4,6两个子数组 1

面试题29 数组中出现次数超过一半的数字

题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 1 class Solution { 2 public: 3 int MoreThanHalfNum_Solution(vector<int> numbers) { 4 if (numbers.size() == 0) 5 return 0; 6 int result = n

剑指offer 面试题40—数组中两个只出现一次的数字

题目: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度O(n),空间复杂度O(1). 基本思想: http://blog.csdn.net/wtyvhreal/article/details/44260321 #include <iostream> using namespace std; int Find1(int n)//从低位开始找第一个1的位置 { int index=0; while((n&1)==0 &&a

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

题目:数组中有一个数字出现的次数超过数组长度的一般,请找出这个数字,例如输入一个长度为9的数组(1,2,3,2,2,2,5,4,2,).由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. 个人第一眼想法是通过一个sort函数,再判断中间那数出现次数,只要出现多于n/2,就直接输出. 一般来说,最为直观的算法面试官都不会满意,那么有没有更优的算法呢? 这种算法是受快速排序算法的启发.在随机快速排序算法中,我们现在数组中随机选择一个数字,然后调整数组中数字的顺序,使得比选中的数字小的数字