数据结构—查找、排序

查找 

电话聊天狂人

给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。

输入格式:

输入首先给出正整数N(≤105),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。

输出格式:

在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。

输入样例:

4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832

输出样例:

13588625832 3
#include<bits/stdc++.h>
using namespace std;
map<string,int>mp;//电话号码类型string,如果是整数就输出不了全部
int main(){
    int n;
    string x,y,id;
    cin>>n;
    int i,j;
    for(i=0;i<n;i++){
        cin>>x>>y;
        mp[x]++;mp[y]++;
    }
    int max=0,cnt=0;
    for(auto i:mp ){
        if(i.second>max){//寻找最大通话次数并记录id(电话号码)
            max=i.second;
            id=i.first;
            cnt=1;
        }
        else if(i.second==max){//else   这样的人不唯一
            cnt++;
        }
    }
    cout<<id<<' '<<max;
    if(cnt>1){
        cout<<' '<<cnt;
    }

    return 0;
}

 词频统计

请编写程序,对一段英文文本,统计其中所有不同单词的个数,以及词频最大的前10%的单词。

所谓“单词”,是指由不超过80个单词字符组成的连续字符串,但长度超过15的单词将只截取保留前15个单词字符。而合法的“单词字符”为大小写字母、数字和下划线,其它字符均认为是单词分隔符。

输入格式:

输入给出一段非空文本,最后以符号#结尾。输入保证存在至少10个不同的单词。

输出格式:

在第一行中输出文本中所有不同单词的个数。注意“单词”不区分英文大小写,例如“PAT”和“pat”被认为是同一个单词。

随后按照词频递减的顺序,按照词频:单词的格式输出词频最大的前10%的单词。若有并列,则按递增字典序输出。

输入样例:

This is a test.

The word "this" is the word with the highest frequency.

Longlonglonglongword should be cut off, so is considered as the same as longlonglonglonee.  But this_8 is different than this, and this, and this...#
this line should be ignored.

输出样例:(注意:虽然单词the也出现了4次,但因为我们只要输出前10%(即23个单词中的前2个)单词,而按照字母序,the排第3位,所以不输出。)

23
5:this
4:is

思路: while(一个字符一个字符的读直到结束,(遇到大写字符就变小写字符并存到字符串s里,且s小于15个字符),否则如果遇到非法字符就把s存到mp里(mp[s]++)并清空s;)

#include<bits/stdc++.h>
using namespace std;
typedef pair<string,int>word;//pair的实现是一个结构体
map<string,int>mp;
vector<word>q;
int cmp(word a,word b){
    if(a.second!=b.second)return a.second>b.second;
    return a.first<b.first;
}//如果每种字符出现的次数不同(a.second!=b.second)就按照出现的次数从大到小排列;如果每种字符出现的次数相同就按照字母的升序排列
int main(){
    string s;
    char c;
    while(scanf("%c",&c)&&c!='#'){//一个字符一个字符的读 遇到#结束
        if((c>='0'&&c<='9')||(c>='a'&&c<='z')||(c>='A'&&c<='Z')||c=='_'){
            if(c>='A'&&c<='Z'){
                c=c-'A'+'a';
            }
            if(s.size()<15){
                s+=c;
            }
        }
        else if(s.size()>0){
            mp[s]++;
            s.clear();
        }
    }
    for(auto i:mp){
        q.push_back({i.first,i.second});
    }
    sort(q.begin(),q.end(),cmp);
    cout<<q.size()<<endl;
    int l=q.size()/10;
    for(int i=0;i<l;i++){// 遍历前10%
        cout<<q[i].second<<':'<<q[i].first<<endl;
    }
    return 0;
}

 集合相似度

给定两个整数集合,它们的相似度定义为:Nc​/Nt​×100%。其中Nc​是两个集合都有的不相等整数的个数,Nt​是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。

输入格式:

输入第一行给出一个正整数N(≤50),是集合的个数。随后N行,每行对应一个集合。每个集合首先给出一个正整数M(≤104),是集合中元素的个数;然后跟M个[0,109]区间内的整数。

之后一行给出一个正整数K(≤2000),随后K行,每行对应一对需要计算相似度的集合的编号(集合从1到N编号)。数字间以空格分隔。

输出格式:

对每一对需要计算的集合,在一行中输出它们的相似度,为保留小数点后2位的百分比数字。

输入样例:

3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3

输出样例:

50.00%
33.33%
#include<bits/stdc++.h>
using namespace std;
set<int >st[55];/
int main(){
    int i,n,m,x,k;
    cin>>n;
    for(i=1;i<=n;i++){//集合是从[1]开始分配空间的
        cin>>k;
        while(k--){
            cin>>x;
            st[i].insert(x);//
        }
    }
    cin>>m;
    while(m--){
        int cnt=0;//
        cin>>x>>k;
        for(auto i:st[k]){
            if(st[x].find(i)!=st[x].end()){
                cnt++;
            }
        }
        double zo=100.0*cnt/(st[x].size()+st[k].size()-cnt);
        printf("%.2lf%%\n",zo);
    }
    return 0;
}

悄悄关注

新浪微博上有个“悄悄关注”,一个用户悄悄关注的人,不出现在这个用户的关注列表上,但系统会推送其悄悄关注的人发表的微博给该用户。现在我们来做一回网络侦探,根据某人的关注列表和其对其他用户的点赞情况,扒出有可能被其悄悄关注的人。

输入格式:

输入首先在第一行给出某用户的关注列表,格式如下:

人数N 用户1 用户2 …… 用户N

其中N是不超过5000的正整数,每个用户ii=1, ..., N)是被其关注的用户的ID,是长度为4位的由数字和英文字母组成的字符串,各项间以空格分隔。

之后给出该用户点赞的信息:首先给出一个不超过10000的正整数M,随后M行,每行给出一个被其点赞的用户ID和对该用户的点赞次数(不超过1000),以空格分隔。注意:用户ID是一个用户的唯一身份标识。题目保证在关注列表中没有重复用户,在点赞信息中也没有重复用户。

输出格式:

我们认为被该用户点赞次数大于其点赞平均数、且不在其关注列表上的人,很可能是其悄悄关注的人。根据这个假设,请你按用户ID字母序的升序输出可能是其悄悄关注的人,每行1个ID。如果其实并没有这样的人,则输出“Bing Mei You”。

输入样例1:

10 GAO3 Magi Zha1 Sen1 Quan FaMK LSum Eins FatM LLao
8
Magi 50
Pota 30
LLao 3
Ammy 48
Dave 15
GAO3 31
Zoro 1
Cath 60

输出样例1:

Ammy
Cath
Pota

输入样例2:

11 GAO3 Magi Zha1 Sen1 Quan FaMK LSum Eins FatM LLao Pota
7
Magi 50
Pota 30
LLao 48
Ammy 3
Dave 15
GAO3 31
Zoro 29

输出样例2:

Bing Mei You
#include<bits/stdc++.h>
using namespace std;
vector<string>q;
set<string>st;
map<string,int>mp;
int main(){
    int i,n,m,x;
    string s;
    cin>>n;
    for(i=0;i<n;i++){
        cin>>s;
        st.insert(s);
    }
    cin>>m;
    int sum=0;
    for(i=0;i<m;i++){
        cin>>s>>x;
        sum+=x;
        mp[s]=x;
    }
    double ave=1.0*sum/m;
    for(auto i:mp){
        if(st.find(i.first)==st.end()&&(i.second>ave)){
            q.push_back(i.first);
        }
    }
    if(q.empty()){
        cout<<"Bing Mei You"<<endl;
    }
    else{
        sort(q.begin(),q.end());
    for(auto i:q){
        cout<<i<<endl;
    }
    }
    return 0;
}

单身狗

“单身狗”是中文对于单身人士的一种爱称。本题请你从上万人的大型派对中找出落单的客人,以便给予特殊关爱。

输入格式:

输入第一行给出一个正整数 N(≤50000),是已知夫妻/伴侣的对数;随后 N 行,每行给出一对夫妻/伴侣——为方便起见,每人对应一个 ID 号,为 5 位数字(从 00000 到 99999),ID 间以空格分隔;之后给出一个正整数 M(≤10000),为参加派对的总人数;随后一行给出这 M 位客人的 ID,以空格分隔。题目保证无人重婚或脚踩两条船。

输出格式:

首先第一行输出落单客人的总人数;随后第二行按 ID 递增顺序列出落单的客人。ID 间用 1 个空格分隔,行的首尾不得有多余空格。

输入样例:

3
11111 22222
33333 44444
55555 66666
7
55555 44444 10000 88888 22222 11111 23333

输出样例:

5
10000 23333 44444 55555 88888
#include<bits/stdc++.h>
using namespace std;
vector<int>q;
set<int>st;
map<int,int>mp;
int main(){
    int m,n,i,x,y;
    cin>>n;
    for(i=0;i<n;i++){
        cin>>x>>y;
        mp[x]=y;mp[y]=x;
    }
    cin>>m;
    for(i=1;i<=m;i++){
        cin>>x;
        st.insert(x);
    }
    for(auto i:st){
        if(st.find(mp[i])==st.end()){
            q.push_back(i);
        }
    }
    sort(q.begin(),q.end());
    cout<<q.size()<<endl;
    int flag=0;
    for(auto i:q){
        if(flag)cout<<' ';
            printf("%05d",i);///一个测试点%05d(每人对应一个 ID 号,为 5 位数字(从 00000 到 99999))
            flag=1;
    }
    return 0;
}

这是二叉搜索树吗?

一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点,

  • 其左子树中所有结点的键值小于该结点的键值;
  • 其右子树中所有结点的键值大于等于该结点的键值;
  • 其左右子树都是二叉搜索树。

所谓二叉搜索树的“镜像”,即将所有结点的左右子树对换位置后所得到的树。

给定一个整数键值序列,现请你编写程序,判断这是否是对一棵二叉搜索树或其镜像进行前序遍历的结果。

输入格式:

输入的第一行给出正整数 N(≤1000)。随后一行给出 N 个整数键值,其间以空格分隔。

输出格式:

如果输入序列是对一棵二叉搜索树或其镜像进行前序遍历的结果,则首先在一行中输出 YES ,然后在下一行输出该树后序遍历的结果。数字间有 1 个空格,一行的首尾不得有多余空格。若答案是否,则输出 NO

输入样例 1:

7
8 6 5 7 10 8 11

输出样例 1:

YES
5 7 6 8 11 10 8

输入样例 2:

7
8 10 11 8 6 7 5

输出样例 2:

YES
11 8 10 7 5 6 8

输入样例 3:

7
8 6 8 5 10 9 11

输出样例 3:

NO
#include<bits/stdc++.h>
using namespace std;
vector<int>q;
int a[1005],flag=1;
void creat(int root,int last){
    if(root>last)return ;
    int left=root+1;
    int right=last;
    if(flag){
        while(left<=last&&a[left]<a[root])left++;
        //left找的是右子树的前序遍历的第一个节点(根节点) 极限:没有右子树 所以<=last 所以left的极限是left=last+1
        while(right>root&&a[right]>=a[root])right--;
        //right找的是左子树最后一个节点->极限:没有左子树 又因最后要用(right=left-1)验证 所以right的极限是right=root
    }
    else{
        while(left<=last&&a[left]>=a[root])left++;
        while(right>root&&a[right]<a[root])right--;
    }
    if(right!=(left-1))return ;
    creat(root+1,right);
    creat(left,last);
    q.push_back(a[root]);
}
int main(){
    int n,i;
    cin>>n;
    for(i=1;i<=n;i++){
        cin>>a[i];
    }
    creat(1,n);
    if(q.size()<n){
        flag=0;
        q.clear();
        creat(1,n);
    }
    if(q.size()==n){
        int c=0;
        cout<<"YES"<<endl;
        for(auto i:q){
            if(c)cout<<' ';
            cout<<i;
            c=1;
        }
    }
    else{
        cout<<"NO"<<endl;
    }
    return 0;
}

二叉搜索树

对于一个无穷的满二叉排序树(如图),节点的编号是1,2,3,…。对于一棵树根为X的子树,沿着左节点一直往下到最后一层,可以获得该子树编号最小的节点;沿着右节点一直往下到最后一层,可以获得该子树编号最大的节点。现在给出的问题是“在一棵树根为X的子树中,节点的最小编号和最大编号是什么?”。请你给出答案。

POJ2309.jpg

输入格式:

输入的第一行给出测试用例的数目,一个整数N。在后面的N行中,每行给出一个整数X(1<=X<=231-1),表示子树树根的编号。

输出格式:

输出N行,第i行给出第i个问题的答案。

输入样例:

2
8
10

输出样例:

1 15
9 11
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,x;
    cin>>n;
    while(n--){
        int t=1;
        cin>>x;
        while(x%(t*2)==0)t*=2;
        t--;
        cout<<x-t<<' '<<x+t<<endl;
    }
    return 0;
}

词典

你刚从滑铁卢搬到了一个大城市,这里的人们讲一种难以理解的外语方言。幸运的是,你有一本字典来帮助你理解它们。

输入格式:

输入第一行是正整数N和M,后面是N行字典条目(最多10000条),然后是M行要翻译的外语单词(最多10000个)。每一个字典条目都包含一个英语单词,后面跟着一个空格和一个外语单词。
输入中的每个单词都由最多10个小写字母组成。

输出格式:

输出翻译后的英文单词,每行一个单词。非词典中的外来词汇输出“eh”。

输入样例:

5 3
dog ogday
cat atcay
pig igpay
froot ootfray
loops oopslay
atcay
ittenkay
oopslay

输出样例:

cat
eh
loops
#include<bits/stdc++.h>
using namespace std;
map<string,string>mp;
set<string>st;
int main(){
    int m,n,i;
    string x,y;
    cin>>n>>m;
    for(i=0;i<n;i++){
        cin>>x>>y;
        mp[y]=x;
        st.insert(y);
    }
    
    for(i=0;i<m;i++){
        cin>>x;
        if(st.find(x)==st.end()){
            cout<<"eh"<<endl;
        }
        else{
            cout<<mp[x]<<endl;
        }
    }

    return 0;
}

排序 

统计工龄

给定公司N名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。

输入格式:

输入首先给出正整数N(≤105),即员工总人数;随后给出N个整数,即每个员工的工龄,范围在[0, 50]。

输出格式:

按工龄的递增顺序输出每个工龄的员工个数,格式为:“工龄:人数”。每项占一行。如果人数为0则不输出该项。

输入样例:

8
10 2 0 5 7 2 5 2

输出样例:

0:1
2:3
5:2
7:1
10:1
#include<bits/stdc++.h>
using namespace std;
map<int,int>mp;//
int main(){
    int n,i,x;
    cin>>n;
    for(i=0;i<n;i++){
        cin>>x;
        mp[x]++;//将数据一一对应存入
    }
    for(auto i:mp){
        cout<<i.first<<":"<<i.second<<endl;
    }
    return 0;
}

寻找大富翁

胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。

输入格式:

输入首先给出两个正整数N(≤106)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。

输出格式:

在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。

输入样例:

8 3
8 12 7 3 20 9 5 18

输出样例:

20 18 12

#include<bits/stdc++.h>//其实把其中所有的long long int 都换成 int,pta 也给过
using namespace std;
vector<long long int>q;
long long int cmp(long long int a,long long int b){
    return a>b;
}
int main(){
    int n,m,i;
    long long int x;
    cin>>n>>m;/?
    m=min(m,n);
    for(i=0;i<n;i++){
        cin>>x;
        q.push_back(x);
    }
    sort(q.begin(),q.end(),cmp);
    cout<<q[0];
    for(i=1;i<m;i++){
        cout<<" "<<q[i];
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m,i;
    int a[1000000];
    cin>>n>>m;
    for (i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for (i=0;i<n;i++){
        if (i>10){break;}
        for (int j=0;j<n-i-1;j++){
            if (a[j]>a[j+1]){
                int t=a[j];a[j]=a[j+1];a[j+1]=t;
            }
        }
    }
    m=min(m,n);
    for (i=n-1;i>n-m-1;i--){
        printf("%d",a[i]);
        if (i!=n-m) printf(" ");
    }
    return 0;
}

点赞狂魔

微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。然而有这么一种人,他们会通过给自己看到的一切内容点赞来狂刷存在感,这种人就被称为“点赞狂魔”。他们点赞的标签非常分散,无法体现出明显的特性。本题就要求你写个程序,通过统计每个人点赞的不同标签的数量,找出前3名点赞狂魔。

输入格式:

输入在第一行给出一个正整数N(≤100),是待统计的用户数。随后N行,每行列出一位用户的点赞标签。格式为“Name K F1​⋯FK​”,其中Name是不超过8个英文小写字母的非空用户名,1≤K≤1000,Fi​(i=1,⋯,K)是特性标签的编号,我们将所有特性标签从 1 到 107 编号。数字间以空格分隔。

输出格式:

统计每个人点赞的不同标签的数量,找出数量最大的前3名,在一行中顺序输出他们的用户名,其间以1个空格分隔,且行末不得有多余空格。如果有并列,则输出标签出现次数平均值最小的那个,题目保证这样的用户没有并列。若不足3人,则用-补齐缺失,例如mike jenny -就表示只有2人。

输入样例:

5
bob 11 101 102 103 104 105 106 107 108 108 107 107
peter 8 1 2 3 4 3 2 5 1
chris 12 1 2 3 4 5 6 7 8 9 1 2 3
john 10 8 7 6 5 4 3 2 1 7 5
jack 9 6 7 8 9 10 11 12 13 14

输出样例:

jack chris john
#include<bits/stdc++.h>
using namespace std;
struct node{
    string name;
    int sum;
    int num;
    double ave;
}a[105];
int cmp(node a,node b){
    if(a.num!=b.num)return a.num>b.num;
    return a.ave<b.ave;
}
int main(){
    int n,i,x;
    string s;
    cin>>n;
    for(i=0;i<n;i++){
        map<int,int>mp;
        cin>>a[i].name>>a[i].sum;
        for(int j=0;j<a[i].sum;j++){//不能while(a[i].sum--)
            cin>>x;
            mp[x]++;
        }
        a[i].num=mp.size();
        a[i].ave=1.0*a[i].sum/a[i].num;
    }
    sort(a,a+n,cmp);
    if(n==1)cout<<a[0].name<<" - -";
    if(n==2)cout<<a[0].name<<' '<<a[1].name<<" -";
    if(n>=3)cout<<a[0].name<<' '<<a[1].name<<' '<<a[2].name;
    return 0;
}

以上作为笔记使用 

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值