给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。
输入格式:
输入首先给出正整数N(≤105),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。
输出格式:
在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。
输入样例:
4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832
输出样例:
13588625832 3
代码长度限制
16 KB
时间限制
600 ms
内存限制
64 MB
解题思路:
题意很好理解 ,无非就是统计电话号码的出现次数并找到出现最多的电话号码中的最小号码值。如有多个号码为该出现次数在统计其数量即可。
但是此题的难点在于电话号码为11位数字很长,倘若我们使用正常的数组打表方法统计个数肯定行不通,这就需要我们利用Hash(散列)的知识了。
1.散列的结构与散列函数:
使用结构体数组的形式进行构造哈夫曼树,倘若每次的一组数据中两个数据都不相同且所有数据中无数据重复出现,则数据‘内存’的大小为2 * 10 ^ 5(即这么多种数据)。而我们肯定是优先考虑取模运算的散列函数进行插入数据操作,对于mod的值取大于2 * 10 ^ 5的最小素数即200003,而数组大小应当大于mod;
2..处理冲突的方法:
在此使用线性探测代码实现较为简单;
3.构造出来结构并决定好处理方法后剩下的就是普通的插入与遍历查找了。
具体代码如下:
//06 - 散列查找1 电话聊天狂人
#include<stdio.h>
#define N 200010
#define mod 200003
#define INF 99999999999
/***mod为比最大数据量大的最小素数***/
typedef long long ll;
struct hash//哈希表结构
{
ll tel;//电话号码
int cnt;//电话号码出现次数
}num[200010];
void Insert(ll a)//线性探测插入函数
{
int flag;
int p = a%mod;
if (!num[p].cnt)//未被占用
{
num[p].cnt++;
num[p].tel = a;
}
else if (num[p].tel == a)
num[p].cnt++;
else if (num[p].cnt&&num[p].cnt != a)//发生冲突
{
//处理冲突--线性探测
flag = 1;//标志号码是否已经出现了
while (num[p].cnt)//找空位或者是后面是否出现该号码
{
if (num[p].tel == a)
{
flag = 0;
num[p].cnt++;
break;
}
p = (p + 1) % mod;
}
//找到空位时跳出
if (flag)
{
num[p].cnt++;
num[p].tel = a;
}
}
}
int main()
{
int n,i;
scanf("%d", &n);
ll a, b;
while (n--)
{
scanf("%lld %lld", &a, &b);
Insert(a);
Insert(b);
}
int ans = 0;//最多的次数
ll tel = INF;//ans中最小tel
for (i = 0; i <= mod; i++)
{
if (num[i].cnt&&num[i].cnt > ans)
{
ans = num[i].cnt;
tel = num[i].tel;
}
else if (num[i].cnt&&num[i].cnt==ans)
{
if (num[i].tel < tel)
tel = num[i].tel;
}
}
int cnt = 0;//记录并列人数
for (i = 0; i <= mod;i++)
if (num[i].cnt == ans)
cnt++;
if (cnt != 1)
printf("%lld %d %d", tel,ans, cnt);
else
printf("%lld %d", tel,ans);
return 0;
}