您的位置:首页 > Web前端

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

2017-04-26 19:58 337 查看
【题目链接】:http://ac.jobdu.com/problem.php?pid=1370

【题目描述】:

题目1370:数组中出现次数超过一半的数字

时间限制:1 秒内存限制:32 兆特殊判题:否提交:3981解决:1146

题目描述:

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

输入:

每个测试案例包括2行:

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

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

输出:

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

样例输入:

9

1 2 3 2 2 2 5 4 2

样例输出:

2

【思路】:

分析:这是一道广为流传的面试题,包括百度、微软和Google在内的多家公司都曾经采用过这个题目。要几十分钟的时间里很好地解答这道题,除了较好的编程能力之外,还需要较快的反应和较强的逻辑思维能力。

看到这道题,我们马上就会想到,要是这个数组是排序的数组就好了。如果是排序的数组,那么我们只要遍历一次就可以统计出每个数字出现的次数,这样也就能找出符合要求的数字了。题目给出的数组没有说是排好序的,因此我们需要给它排序。排序的时间复杂度是O(nlogn),再加上遍历的时间复杂度O(n),因此总的复杂度是O(nlogn)。

接下来我们试着看看能不能想出更快的算法。前面思路的时间主要是花在排序上。我们可以创建一个哈希表来消除排序的时间。哈希表的键值(Key)为数组中的数字,值(Value)为该数字对应的次数。有了这个辅助的哈希表之后,我们只需要遍历数组中的每个数字,找到它在哈希表中对应的位置并增加它出现的次数。这种哈希表的方法在数组的所有数字都在一个比较窄的范围内的时候很有效。我们要么需要创建一个很大的哈希表,要么需要设计一个很复杂的方法来计算哈希值。因此总体说来这个方法还不是很好。

前面两种思路都没有考虑到题目中数组的特性:数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要多。因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。如果次数为零,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。

【代码】:

#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <set>
#include <stack>
#include <math.h>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
const LL MOD = 999999997;
int dir4[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};
int dir8[8][2]= {{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};
/*Super waigua */
inline int read(){
int  c=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
return c*f;
}

int a[maxn];
bool input_invalid = false;

/*考虑无效的输入,判断输入数组是否无效*/
bool check_invalid_array(int *a,int n)
{
input_invalid=false;
if(a==NULL || n<=0) input_invalid=true;
return input_invalid;
}

/*考虑无效输入,判断数组中出现频率最高的数字没有达到要求*/
bool check_more_than_half(int *a,int n,int k)
{
int times=0;
for(int i=0; i<n; ++i)
{
if(a[i]==k) ++times;
}
bool is_more_than_half = true;
if( times*2<=n )
{
input_invalid=true;
is_more_than_half=false;
}
return is_more_than_half;
}

int more_than_half(int *a,int n)
{
/*输入不合法*/
if(check_invalid_array(a,n)) return -1;

int ret= a[0];
int times=1;
for(int i=0; i<n; ++i)
{
if(times ==0)
{
ret=a[i];
times=1;
}
else if(a[i]==ret) ++times;
else --times;
}
/*不满足题目要求*/
if(!check_more_than_half(a,n,ret)) return -1;
return ret;
}

int main()
{
//freopen("in.txt","r",stdin);
int n,m;
while(~scanf("%d",&n))
{
for(int i=0; i<n; ++i) a[i]=read();
printf("%d\n",more_than_half(a,n));
}
return 0;
}

/**************************************************************
Problem: 1370
User: herongwei
Language: C++
Result: Accepted
Time:30 ms
Memory:1908 kb
****************************************************************/


【参考】:

http://zhedahht.blog.163.com/blog/#m=0&t=1&c=fks_081075092084086069082074084070080087080066083082
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: