PTA:电话聊天狂人
题目描述
给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。
输入格式:
输入首先给出正整数N(≤105),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。
输出格式:
在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。
输入样例:
4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832
输出样例:
13588625832 3
解法1(非散列):对每个输入的号码直接排序即可,然后依次进行相应统计。这个方法当然就好在代码写起来很快,很简洁。但是失去了一次练习散列和指针的机会。
解法2:运用散列,相同的元素对应的关键码一定相同,大大加快了查找相同元素的时间。那么对于这里,无法确定一个关键码最多可能对应多少Key的情况,可以选择用链表数组来进行操作。
重要步骤:确定散列函数。这里就用较为简单的取余法,进行散列。那么此时,自然是要求出一个合适的素数M。那么首先要确定M肯定大于2N,因为有可能所有电话号码都不一样。那求这个M可以有很多方法,可以往2N后不断找奇数,然后碰到一个素数就停止。我的方法比较暴力,直接把所有可能的M值都存在一个素数数组里面,然后输入N以后就直接遍历整个数组找到正确的M。
重要定义:
struct k
{
char number[12];
int cishu;
struct k *next=NULL;
};
k *x[300000];
x即链表数组,头元素就是第一个元素,手动增加一个哨兵元素也可以,但是这里没有哨兵元素也不会很麻烦。这里还要注意一定要定义计数器。
代码中的重要函数:
1.myfind(char [ ]):其目标就是找到合适的位置pos,若该链上有相同元素则让该Key的计数器+1即可,并且直接返回-1,代表不用再进行其他操作。相反,倘若没有找到,则返回其位置pos。
2.myinsert(char [ ]):那么很显然这是个插入元素的函数,在输入时就可以直接调用插入。用myinsert时先调用myfind,返回-1就自然不用再进行操作,直接出去。倘若返回的pos那么代表要进行操作,然后这里需要特判是否要插入的链表还没有一个Key(增加了一个空的头节点的话,也就是哨兵元素的话就不用特判),然后视具体情况进行相应简单插入操作就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
bool visited[300000];
int prime[200000];
int n,M;
int EE(int n)
{
for(int i=0;i<=n;++i)visited[i]=false;
for(int i=2;i*i<=n;++i)
if(!visited[i])
for(int j=i*i;j<=n;j+=i)
visited[j]=true;
int k=0;
for(int i=2;i<=n;++i)
if(!visited[i])
prime[k++]=i;
return k;
}
struct k
{
char number[12];
int cishu;
struct k *next=NULL;
};
k *x[300000];
int maxci=-1,maxren=0;
char ans[12];
int myfind(char y[])
{
int pos=atoi(y+5)%M;
k *p=x[pos];
while(p)
{
if(strcmp(p->number,y)==0){
p->cishu++;
return -1;}
p=p->next;
}
return pos;
}
void myinsert(char y[])
{
int pos=myfind(y);
if(pos!=-1){
if(x[pos]==NULL)
{
x[pos]=(k*)malloc(sizeof(k));
x[pos]->cishu=1;
strcpy(x[pos]->number,y);
x[pos]->next=NULL;
}
else
{
k *p=x[pos]->next,*t=(k*)malloc(sizeof(k));
t->cishu=1;
strcpy(t->number,y);
t->next=p;
x[pos]->next=t;
}
}
}
void scanlist()
{
for(int i=0;i<M;++i)
{
k *p=x[i];
while(p)
{
if(p->cishu>maxci)
{
maxci=p->cishu;
maxren=1;
strcpy(ans,p->number);
p=p->next;
continue;
}
if(p->cishu==maxci)
{
maxren++;
if(strcmp(p->number,ans)<0)
strcpy(ans,p->number);
p=p->next;
continue;
}
p=p->next;
}
}
}
int main()
{
EE(200009);
char x1[12],x2[12];
cin>>n;
for(int i=0;;++i)
{
if(prime[i]>2*n)
{
M=prime[i];
break;
}
}
for(int i=0;i<n;++i)
{
cin>>x1;
myinsert(x1);
cin>>x2;
myinsert(x2);
}
scanlist();
cout<<ans<<' '<<maxci;
if(maxren!=1)
cout<<' '<<maxren;
}