数据结构 学校练习 第一次

7-1 求链式线性表的倒数第K项

给定一系列正整数,请设计一个尽可能高效的算法,查找倒数第K个位置上的数字。

输入格式:

输入首先给出一个正整数K,随后是若干非负整数,最后以一个负整数表示结尾(该负数不算在序列内,不要处理)。

输出格式:

输出倒数第K个位置上的数据。如果这个位置不存在,输出错误信息NULL

输入样例:

4 1 2 3 4 5 6 7 8 9 0 -1

输出样例:

7

解题思路:首先存入所有的数据,注意负整数不能存,注意最终跳出NULL的条件,保证k在数组的范围中就行

#include<iostream>
#include<vector>

using namespace std;

int k;
vector<int>v;

int main()
{
    cin >> k;
    while(1)
    {
        int num;
        cin >> num;
        if(num < 0) break;
        v.push_back(num);
    }
    
    int n = v.size();
    
    if(k < 0 || k > n) 
    {
        puts("NULL");
        return 0;
    }
    
    cout << v[n - k] << endl;
    return 0;
}

7-2 两个有序链表序列的交集

已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。

输入格式:

输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。

输出格式:

在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL

输入样例:

1 2 5 -1
2 4 5 8 10 -1

输出样例:

2 5

解题思路:用哈希表存第一个表每一个数的个数,再遍历第二个表,找到重复的即可,注意可能会有连续好几个一样的不能使用unordered_set去存

#include<iostream>
#include<unordered_map>
#include<vector>

using namespace std;

unordered_map<int , int>mp;
vector<int>res;

int main()
{
    while(1)
    {
        int num;
        cin >> num;
        if(num == -1) break;
        mp[num] ++;
    }
    
    while(1)
    {
        int num;
        cin >> num;
        if(num == -1) break;
        if(mp[num]) res.push_back(num) , mp[num] --;
    }
    
    if(!res.size()) puts("NULL");
    else 
    {
        for(int i = 0;i < res.size();i ++)
        {
            if(i) cout << " ";
            cout << res[i];
        }
        //cout << endl;
    }
    return 0;
}

7-3 多项式A除以B(仔细看这道题其实是天梯赛的题)

这也是这四道题中最难的一道题了

这仍然是一道关于A/B的题,只不过A和B都换成了多项式。你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数。

输入格式:

输入分两行,每行给出一个非零多项式,先给出A,再给出B。每行的格式如下:

N e[1] c[1] ... e[N] c[N]

其中N是该多项式非零项的个数,e[i]是第i个非零项的指数,c[i]是第i个非零项的系数。各项按照指数递减的顺序给出,保证所有指数是各不相同的非负整数,所有系数是非零整数,所有整数在整型范围内。

输出格式:

分两行先后输出商和余,输出格式与输入格式相同,输出的系数保留小数点后1位。同行数字间以1个空格分隔,行首尾不得有多余空格。注意:零多项式是一个特殊多项式,对应输出为0 0 0.0。但非零多项式不能输出零系数(包括舍入后为0.0)的项。在样例中,余多项式其实有常数项-1/27,但因其舍入后为0.0,故不输出。

输入样例:

4 4 1 2 -3 1 -1 0 -1
3 2 3 1 -2 0 1

输出样例:

3 2 0.3 1 0.2 0 -1.0
1 1 -3.1

解题思路:

第一点就是,得弄清楚多项式怎么除

需要计算的每一个数有两个值需要求一个是指数一个是系数
指数的求法就是被除数的第i个指数减除数的第i个的指数
系数求法就是被除数的第i个除以除数第i个系数

将商第i项去乘除式,把积写在被除式下面(同类项对齐),消去相等项,把不相等的项结合起来,就是需要更新的数

第二点就是,怎么存

哈希表和结构体去存每一个除数和被除数,注意最终结果剩下的余数一定是被除数(无法被再除)

 最后就是怎么表达了

#include<iostream>
#include<vector>
#include<algorithm>
#include<unordered_map>

using namespace std;

const int N = 1e5 + 10;
unordered_map<int , double>A , res;
struct nodes
{
    int e;// 指数
    double c;// 系数
}B[N];

bool check(double x)
{
    if(x > 0 && x >= 0.05) return true;
    else if(x < 0 && x <= -0.05) return true;
    return false;
}

void print(int t , int w , int m)
{
    if(!w) 
    {
        cout << " 0 0.0";
        return;
    }
    
    if(!t) // 商
    {
        for(int i = m;i >= 0;i --)
        {
            int x = i;
            double y = res[i];
            if(check(y)) printf(" %d %.1lf" , x, y);
        }
    }
    else
    {
        for(int i = m;i >= 0;i --)
        {
            int x = i;
            double y = A[i];
            if(check(y)) printf(" %d %.1lf" ,x, y);
        }
    }
}

int main()
{
    int _max = -1;
    int cnt = 0;
    for(int i = 0;i < 2;i ++)
    {
        int k;
        cin >> k;
        while(k --)
        {
            int a;
            double b;
            cin >> a >> b;
            if(!i) A[a] = b , _max = max(_max , a);
            else B[cnt].e = a , B[cnt ++].c = b;
        }
    }
    
    // 得到的数有两个一个是指数一个是系数
    // 指数的求法就是被除数的第i个指数减除数的第i个的指数
    // 系数求法就是被除数的第i个除以除数第i个系数
    for(int i = _max;i >= B[0].e;i --)
    {
        int x_e = i - B[0].e;
        double x_c = A[i] / B[0].c;
        
        res[x_e] = x_c;
        
        for(int j = 0;j < cnt;j ++)
            A[B[j].e + x_e] -= x_c * B[j].c;
    }
    
    // A就是余数 , res就是商
    int cnt_r = 0 , cnt_q = 0;
    for(int i = 0;i <= _max;i ++)
    {
        double x = res[i];
        double y = A[i];
        if(check(x)) cnt_q ++;
        if(check(y)) cnt_r ++;
    }
    
    // 商的输出
    cout << cnt_q;
    print(0 , cnt_q , _max);
    
    cout << endl;
    
    // 余数的输出
    cout << cnt_r;
    print(1 , cnt_r , _max);
}

7-4 喊山

喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤。呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的。原来它是彝族先民用来求援呼救的“讯号”,慢慢地人们在生活实践中发现了它的实用价值,便把它作为一种交流工具世代传袭使用。(忽略人的照片)

一个山头呼喊的声音可以被临近的山头同时听到。题目假设每个山头最多有两个能听到它的临近山头。给定任意一个发出原始信号的山头,本题请你找出这个信号最远能传达到的地方。

输入格式:

输入第一行给出3个正整数nmk,其中n(≤10000)是总的山头数(于是假设每个山头从1到n编号)。接下来的m行,每行给出2个不超过n的正整数,数字间用空格分开,分别代表可以听到彼此的两个山头的编号。这里保证每一对山头只被输入一次,不会有重复的关系输入。最后一行给出k(≤10)个不超过n的正整数,数字间用空格分开,代表需要查询的山头的编号。

输出格式:

依次对于输入中的每个被查询的山头,在一行中输出其发出的呼喊能够连锁传达到的最远的那个山头。注意:被输出的首先必须是被查询的个山头能连锁传到的。若这样的山头不只一个,则输出编号最小的那个。若此山头的呼喊无法传到任何其他山头,则输出0。

输入样例:

7 5 4
1 2
2 3
3 1
4 5
5 6
1 4 5 7

输出样例:

2
6
4
0

解题思路: 这道题要求的就是离给定询问距离最远并且编号最小的山头的编号,一开始想的是并查集,显然并查集是写不出来的,因为询问都是一个点,并且返回的结果并不是,这个节点的祖宗节点,而是距离最远并且编号最小的山头,然后应该想到的就是bfs,计算出每一个给定询问的和每个相邻节点的距离,最终遍历一遍距离数组即可得到答案

bfs用什么实现?应该用队列,对于每一个节点不能重复遍历,需要有一个st去标记,在每一轮计算距离的时候,顺便计算一下最大距离,一边下边使用。

#include<iostream>
#include<unordered_map>
#include<vector>
#include<queue>
#include<cstring>

using namespace std;
const int N = 1e5 + 10 , INF = 0x3f3f3f3f;
int n , m , k;
unordered_map<int , vector<int>>mp;
bool st[N];
queue<int>q;
int dist[N];

void bfs(int u)
{
    int max_dist = -1;
    while(!q.empty())
    {
        int t = q.front();
        q.pop();
        st[t] = true;
        
        max_dist = max(max_dist , dist[t]);
        
        for(int i : mp[t])
        {
            if(!st[i] && !dist[i]) 
            {
                dist[i] = dist[t] + 1;
                q.push(i);
            }
        }
    }
    //cout << max_dist << endl;
    for(int i = 0;i <= n;i ++)
        if(dist[i] == max_dist) 
        {
            cout << i << endl;
            return ;
        }
}

int main()
{
    memset(st , false , sizeof st);
    cin >> n >> m >> k;
    for(int i = 0;i < m;i ++)
    {
        int a , b;
        cin >> a >> b;
        // 注意是无向图
        mp[a].push_back(b);
        mp[b].push_back(a);
    }
    
    while(k --)
    {
        int a;
        cin >> a;
        
        memset(st , false , sizeof st);
        memset(dist , 0 , sizeof dist);
        q.push(a);
        bfs(a);
    }
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值