21级数据结构与算法实验7——查找表

目录

7-1 电话聊天狂人

7-2 两个有序序列的中位数

7-3 词频统计

7-4 集合相似度

7-5 悄悄关注

7-6 单身狗

7-7 词典

7-8 这是二叉搜索树吗?

7-9 二叉搜索树

7-1 电话聊天狂人

分数 25

作者 DS课程组

单位 浙江大学

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

输入格式:

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

输出格式:

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

输入样例:

4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832

输出样例:

13588625832 3

代码长度限制

16 KB

时间限制

600 ms

内存限制

64 MB

参考代码:C++(g++)

#include<bits/stdc++.h>
using namespace std;
map<string,int>f;//映射
map<string,int>::iterator it;//迭代器
int main() {
    int n;
    cin>>n;
    while(n--){
        string a,b;
        cin>>a>>b;
        f[a]++,f[b]++;//通话次数
    }
    int maxn=0,cnt;string id;
    for(it=f.begin();it!=f.end();it++) {
        if(it->second>maxn){//maxn找最大的通话次数
            maxn=it->second;
            id=it->first;//id最大通话数的人且map自动按key升序是最小的编号
            cnt=1;//cnt计数
        }
        else if(it->second==maxn)cnt++;//有相同次数多狂人统计人数
    }
    cout<<id<<" "<<maxn;
    if(cnt>1)cout<<" "<<cnt;
    return 0;
}

7-2 两个有序序列的中位数

分数 25

作者 DS课程组

单位 浙江大学

已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列A0​,A1​,⋯,AN−1​的中位数指A(N−1)/2​的值,即第⌊(N+1)/2⌋个数(A0​为第1个数)。

输入格式:

输入分三行。第一行给出序列的公共长度N(0<N≤100000),随后每行输入一个序列的信息,即N个非降序排列的整数。数字用空格间隔。

输出格式:

在一行中输出两个输入序列的并集序列的中位数。

输入样例1:

5
1 3 5 7 9
2 3 4 5 6

输出样例1:

4

输入样例2:

6
-100 -10 1 1 1 1
-50 0 2 3 4 5

输出样例2:

1

代码长度限制

16 KB

时间限制

200 ms

内存限制

64 MB

参考代码:C++(g++)

#include<bits/stdc++.h>
using namespace std;
int main(){
    vector<int>a;
    int n;
    cin>>n;
    for(int i=0;i<2*n;i++){
        int x;
        cin>>x;
        a.push_back(x);
    }
    sort(a.begin(),a.end());
    cout<<a[n-1];
}

7-3 词频统计

分数 30

作者 DS课程组

单位 浙江大学

请编写程序,对一段英文文本,统计其中所有不同单词的个数,以及词频最大的前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

感谢武汉理工大学的郭小兵老师修正测试数据!

代码长度限制

16 KB

时间限制

2000 ms

内存限制

64 MB

参考代码:C++(g++)

#include<bits/stdc++.h>
using namespace std;
typedef pair<string,int>word;//pair的实现是一个结构体,主要的两个成员变量是first,second
map<string,int>mp;//映射
map<string,int>::iterator it;//迭代器
vector<word> q;//容器
int cmp(word a,word b){
    if(a.second!=b.second) return a.second>b.second;//出现次数
    else return a.first<b.first;    //   字母序
}
int main(){
    string s;
    char x;
    while(scanf("%c",&x)&&x!='#'){ //  一个字符一个字符的读  遇到 # 结束
        if( (x>='A'&&x<='Z') || (x>='a'&&x<='z') || (x>='0'&&x<='9') || x=='_'){
            if(x>='A'&&x<='Z') x=x-'A'+'a'; // 都转化成小写
            if(s.size()<15)s+=x;//如果大于长度15只要前十五个
        }
        else if(s.size()>0)mp[s]++,s.clear();   //遇到非合法字符存到map<string,int> 中去
    }
    for(it=mp.begin();it!=mp.end();it++)      //  把map中的信息转入到vector中去
        q.push_back({it->first,it->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;
}

7-4 集合相似度

分数 25

作者 陈越

单位 浙江大学

给定两个整数集合,它们的相似度定义为: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%

代码长度限制

16 KB

时间限制

500 ms

内存限制

64 MB

参考代码:C++(g++)

#include <bits/stdc++.h>
using namespace std;
set<int>st[55];
int main(){
    int n,k;
    cin>>n;
    for(int i=1;i<=n;i++){
        int m;
        cin>>m;
        while(m--){
            int x;
            cin>>x;
            st[i].insert(x);
        }
    }
    cin>>k;
    while(k--){
        int a,b,cnt=0;;
        cin>>a>>b;
        for(auto i:st[a])
            if(st[b].find(i)!=st[b].end())cnt++;
        double rate=100.0*cnt/(st[a].size()+st[b].size()-cnt);
        printf("%.2lf%%\n",rate);
    }
}

补充:

set就是集合,STL的set用二叉树实现,集合中的每个元素只出现一次(参照数学中集合的互斥性),并且是排好序的(默认按键值升序排列)

访问元素的时间复杂度是O ( log ⁡ 2 n ) O(\log_2n)O(log2n)

set<int> q;     //以int型为例 默认按键值升序

set<int,greater<int>> p;  //降序排列

int x;

q.insert(x); //将x插入q中

q.erase(x); //删除q中的x元素,返回0或1,0表示set中不存在x

q.clear(); //清空q

q.empty(); //判断q是否为空,若是返回1,否则返回0

q.size(); //返回q中元素的个数

q.find(x); //在q中查找x,返回x的迭代器,若x不存在,则返回指向q尾部的迭代器即 q.end()

q.lower_bound(x); //返回一个迭代器,指向第一个键值不小于x的元素

q.upper_bound(x); //返回一个迭代器,指向第一个键值大于x的元素

q.rend();   //返回第一个元素的的前一个元素迭代器

q.begin();   //返回指向q中第一个元素的迭代器

q.end();  //返回指向q最后一个元素下一个位置的迭代器

q.rbegin();  //返回最后一个元素

7-5 悄悄关注

分数 25

作者 陈越

单位 浙江大学

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

输入格式:

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

人数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

代码长度限制

16 KB

时间限制

200 ms

内存限制

64 MB

参考代码:C++(g++)

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

7-6 单身狗

分数 25

作者 陈越

单位 浙江大学

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

输入格式:

输入第一行给出一个正整数 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

代码长度限制

16 KB

时间限制

200 ms

内存限制

64 MB

参考答案C++(g++)

#include <bits/stdc++.h>
using namespace std;
int t[10001];
vector<int>a;
map<int,int>mp;
set<int>st;
int main(){
    int n,m;
    cin>>n;
    for(int i=0;i<n;i++){
        int a,b;
        cin>>a>>b;
        mp[a]=b,mp[b]=a;
    }
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>t[i];
        st.insert(t[i]);
    }
    int cnt=0;
    for(int i=1;i<=m;i++){
        if(st.find(mp[t[i]])==st.end()){
            cnt++;
            a.push_back(t[i]);
        }
    }
    sort(a.begin(), a.end());
    cout<<cnt<<endl;
    int flag=0;
    for(auto i:a){
        if(flag)printf(" ");
        printf("%05d",i);
        flag++;
    }
}

7-7 词典

分数 15

作者 hcx11333

单位 山东大学(威海)

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

输入格式:

输入第一行是正整数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

代码长度限制

16 KB

时间限制

1000 ms

内存限制

64 MB

参考代码:C++(g++)

#include <bits/stdc++.h>
using namespace std;
int main()
{
    map<string,string> mp;
    int n,m;
    string a,b;
    cin>>n>>m;
    while(n--){
        cin>>a>>b;
        mp[b]=a;
    }
    while(m--){
        cin>>a;
        if(!mp.count(a))cout<<"eh"<<endl;
        else cout<<mp[a]<<endl;
    }
}

7-8 这是二叉搜索树吗?

分数 25

作者 陈越

单位 浙江大学

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

  • 其左子树中所有结点的键值小于该结点的键值;

  • 其右子树中所有结点的键值大于等于该结点的键值;

  • 其左右子树都是二叉搜索树。

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

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

输入格式:

输入的第一行给出正整数 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

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

参考代码:C++(g++)

#include<bits/stdc++.h>
using namespace std;
int num[1010],n,pre[1010];
int flag=1;
void dfs(int l,int r){
    if(l>r)return;
    int i=l+1,j=r;
    if(flag){
        while(i<=r&&pre[i]<pre[l])i++;
        while(j>l&&pre[j]>=pre[l]) j--;
    }else {
        while(i<=r&&pre[i]>=pre[l])i++;
        while(j>l&&pre[j]<pre[l])j--;
    }
    dfs(l+1,j);
    dfs(i,r);
    num[++num[0]]=pre[l];
}
int main(){
    cin>>n;
    int i,k,j;
    for(i=1;i<=n;i++)
        cin>>pre[i];
    dfs(1,n);
    if(num[0]!=n){
        flag=0;
        num[0]=0;
        dfs(1,n);
    }
    if(num[0]!=n)cout<<"NO";
    else{
        cout<<"YES\n"<<num[1];
        for(i=2;i<=num[0];i++)
            cout<<" "<<num[i];
    }
}

7-9 二叉搜索树

分数 20

作者 李廷元

单位 中国民用航空飞行学院

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

输入格式:

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

输出格式:

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

输入样例:

2
8
10

输出样例:

1 15
9 11

代码长度限制

16 KB

时间限制

1000 ms

内存限制

64 MB

参考代码:C++(g++) 

#include<bits/stdc++.h>
using namespace std;
int getheight(int temp){
    int height=0;
    while(temp%2==0){
        temp = temp/2;
        height++;
    }
    return height;
}
int main(){
    int n,i,temp,height,max,min;
    cin>>n;
    for(i=0;i<n;i++){
       int j=0,q=1,p=1;
       cin>>temp;
       height=getheight(temp);
       max=min=temp;
       while(j<height){
           min=min-q;
           q=q*2;
           max=max+p;
           p=p*2;
           j++;
       }
       cout<<min<<' '<<max<<endl;
    }
}

参考代码二:

看图找规律, 如果把 数 都压到最底下看 就是1, 2, 3, 4, 5, 6, 7, 8, ...

​ 对于给定x, 它和两边的数字差就是它到两边的宽度, 而 宽度 = 高度 - 1( 这里的高度是从叶子节点(高度为 1 )开始算的 ) ; 同时我们发现, 从左到右, 以 1 开始的一层 都能被 1 整除, 不能被 2 整除, 同样, 以 2 开始的一层的数, 都能被 2 整除, 但不能被 4 整除, 以此类推,,,,就能找到 x 所在的层数

#include <bits/stdc++.h>
using namespace std;
int main() {
    int N;
    cin>>N;
    while(N--){
        long long int x,y=1;
        cin>>x;
        while(x%(y*2)==0)y*=2;
        y--;
        cout<<x-y<<" "<<x+y<<endl;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

救救孩子√

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值