给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。
输入格式:
输入首先给出正整数N(N≤10^5),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。
输出格式:
在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。
输入样例:
4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832
输出样例:
13588625832 3
思路:可以用排序,可以用long long型的visit数组或者hash表,我用的是Hash表,处理冲突用的分离链接法,映射取的是电话号码的后五位.(用了STL的map[string]最后一个测试点超时了)
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn=200050;
typedef struct Node Node;
typedef struct HashTable HashTable;
struct Node{
int val=0;
Node *next;
char str[15];
};
struct HashTable{
int Size=0;
Node node[maxn];
};
bool isprime(int n){
for(int i=2;i<=sqrt(n);i++){
if(n%i==0)
return false;
}
return true;
}
HashTable H;//哈希表
int N;
void Insert(char *str3,int m){
Node *head,*first;
head=first=&H.node[m];
head=head->next;
while(head){
if(strcmp(str3,head->str)==0){
(head->val)++;
return;
}
head=head->next;
}
Node *p=new Node();
p->next=first->next;
strcpy(p->str,str3);
first->next=p;
}
void scanAndoutput(){
char str4[15];
int Max=0,cnt=0;
Node *pHead;
for(int i=0;i<H.Size;i++){
pHead=H.node[i].next;
while(pHead){
(pHead->val)++;
if(pHead->val>Max){
Max=pHead->val;
cnt=1;
strcpy(str4,pHead->str);
}
else if(pHead->val==Max){
cnt++;
if(strcmp(str4,pHead->str)>0){
strcpy(str4,pHead->str);
}
}
pHead=pHead->next;
}
}
printf("%s %d",str4,Max);
if(cnt>1)
printf(" %d\n",cnt);
}
int main(){
//freopen("in.txt","r",stdin);
int t;
char str1[15],str2[15];
scanf("%d",&N);
H.Size=2*N;
while(1){
if(isprime(H.Size))
break;
H.Size++;
}//H.Size为哈希表的长度
for(int i=0;i<H.Size;i++){
Node *h=new Node();
h=&H.node[i];
H.node[i].next=NULL;
}//把每个头结点初始化
for(int i=0;i<N;i++){
scanf("%s%s",str1,str2);
t=atoi(str1+6);//字符串转化为数字
Insert(str1,t%H.Size);//除留余数法
t=atoi(str2+6);
Insert(str2,t%H.Size);
}//插入模块
scanAndoutput();
Node *P,*temp;
for(int i=0;i<H.Size;i++){
P=H.node[i].next;
while(P){
temp=P->next;
delete(P);
P=temp;
}
}//释放空间
return 0;
}