《AcWing暑假每日一题》Week 5

7.4 树查找

给定一棵包含 n 个结点(编号 1∼n)的完全二叉树的层序遍历序列,请按照从左到右的顺序输出该树第 k 层的全部结点编号。

输入格式
第一行包含整数 n。

第二行包含 n 个整数,表示该二叉树的层序遍历序列。

第三行包含整数 k。

输出格式
共一行,按照从左到右的顺序输出该树第 k 层的全部结点编号。

数与数之间用单个空格隔开。

若无该层结点,则输出 EMPTY。

数据范围
1≤n≤1000,
1≤k≤20
输入样例:
4
1 2 3 4
2
输出样例:
2 3

解题思路 :

因为是完全二叉树,并且树是以层次遍历的顺序给出,所以利用完全二叉树的性质,可以假设第一层根节点的下标是1, 第二层的下标就是2, 3 第三层就是4,5,6,7, 第四层就是8,9,10,11,12,13,14,15。由此类推 我们可以发现第i层的第一个元素的下标就是2^(i - 1),且最后一个元素的下标就是2 ^ i - 1, 由此直接进行循环,题目说从k层,也就是从2 ^ (k - 1)开始,但是不确定k是否为最后一层,因为最后一层不一定是满的,所以要在n, 2 ^ (k - 1)中取一个最小值。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N];
int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++)    
    cin >> a[i];
    int k;
    cin >> k;
    bool flag = 0;
    for(int i = (1 << (k - 1)); i <= min((1 << k) - 1, n); i ++)// 1 << (k - 1) 等价于 2 ^ (k - 1)
    {
        flag = 1;
        cout << a[i] << ' ';
    }
    if(!flag)    
    cout << "EMPTY" << endl;
    return 0;
}

7.5 日期类

编写一个日期类,要求按 xxxx-xx-xx 的格式输出日期,实现加一天的操作。

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

每组数据占一行,包含 3 个用空格隔开的整数,分别表示年月日。

输出格式
每组数据输出一行,一个结果,按 xxxx-xx-xx 的格式输出,表示输入日期的后一天的日期。

数据范围
输入日期保证合法且不会出现闰年。
年份范围 [1000,3000]
输入样例:
2
1999 10 20
2001 1 31
输出样例:
1999-10-21
2001-02-01

解题思路:

没什么好说的,分类讨论一下就ok。

AC代码:

#include<iostream>
using namespace std;
int md[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int main()
{
    int n; 
    cin >> n;
    while (n--)
    {
        int y, m, d; cin >> y >> m >> d;
        d++;
        if (d > md[m]) d = 1, m++;
        if( m == 13) m = 1, y++;
        printf("%d-%02d-%02d\n", y, m, d);
    }
    return 0;
}

7.6 幂次方

对任意正整数 N,计算 XNmod233333 的值。

输入格式
共一行,两个整数 X 和 N。

输出格式
共一行,一个整数,表示 XNmod233333 的值。

数据范围
1≤X,N≤109
输入样例:
2 5
输出样例:
32

解题思路 :

快速幂模板,记得开long long

AC代码:

#include <iostream>
#define ll long long
using namespace std;
const int mod = 233333;
ll F(ll a, ll b)
{
    ll ans = 1;
    while (b)
    {
        if (b & 1)
        {
            ans *= a;
            ans %= mod;

        }
        b >>= 1;
        a *= a;
        a %= mod;
    }
    return ans;
}
int main()
{
    ll n, m;
    cin >> n >> m;
    cout << F(n,m) << endl;
    return 0;
}

7.7 连通图

给定一个无向图和其中的所有边,判断这个图是否所有顶点都是连通的。

输入格式
输入包含若干组数据。

每组数据第一行包含两个整数 n 和 m,表示无向图的点和边数。

接下来 m 行,每行包含两个整数 x,y,表示点 x 和点 y 相连。

点的编号从 1 到 n。

图中可能存在重边和自环。

输出格式
每组数据输出一行,一个结果,如果所有顶点都是连通的,输出 YES,否则输出 NO。

数据范围
输入最多包含 10 组数据。
1≤n≤1000,
1≤m≤5000,
1≤x,y≤n
输入样例:
4 3
1 2
2 3
3 2
3 2
1 2
2 3
输出样例:
NO
YES

解题思路 :

并查集模板题 O(nlogn)
把p[i] = i的结点看作一个集合的父节点, 然后进行各种合并操作

AC代码 :

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m;
int p[N], s[N];
int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}
int main()
{
    while (cin >> n >> m)
    {
        for (int i = 1; i <= n; i ++ ) p[i] = i, s[i] = 1;
        while (m -- )
        {
            int a, b;
            cin >> a >> b;

            a = find(a), b = find(b);
            if (a != b) 
            {
                s[b] += s[a];
                p[a] = b;
            }
        }
        if (s[find(1)] == n) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

7.8 :手机键盘

请你计算按照手机键盘(9 键输入法)输入字母的方式,键入给定字符串(由小写字母构成)所花费的时间。

具体键入规则和花费时间如下描述:

对于同一键上的字符,例如 a,b,c 都在 “1” 键上,输入 a 只需要按一次,输入 c 需要连续按三次。

如果连续两个字符不在同一个按键上,则可直接按,如:ad 需要按两下,kz 需要按 6 下。

如果连续两字符在同一个按键上,则两个按键之间需要等一段时间,如 ac,在按了 a 之后,需要等一会儿才能按 c。

现在假设每按一次需要花费一个时间段,等待时间需要花费两个时间段。

输入格式
输入包含多组测试数据。

每组数据占一行,包含一个由小写字母构成的字符串。

输出格式
对于每组输入,输出一行结果表示键入给定字符串所需要花费的时间。

数据范围
每个输入最多包含 100 组测试数据。
所有字符串的长度都不超过 100。

输入样例:
bob
www
输出样例:
7
7

解题思路 :

多动手少动脑 打表

AC代码 :

#include <bits/stdc++.h>
using namespace std;
int cost[] = {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 4};
int btn[] = {2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9};
int main()
{
    for (string s; cin >> s;)
    {
        int v = 0;
        char ls = ' ';
        for (auto x : s)
        {
            v += cost[x - 'a'];
            if (ls != ' ' && btn[x - 'a'] == btn[ls - 'a'])
                v += 2;
            ls = x;
        }
        cout << v << endl;
    }
    return 0;
}

7.9 二叉树遍历

假定一棵二叉树的每个结点都用一个大写字母描述。

给定这棵二叉树的前序遍历和中序遍历,求其后序遍历。

输入格式
输入包含多组测试数据。

每组数据占两行,每行包含一个大写字母构成的字符串,第一行表示二叉树的前序遍历,第二行表示二叉树的中序遍历。

输出格式
每组数据输出一行,一个字符串,表示二叉树的后序遍历。

数据范围
输入字符串的长度均不超过 26。

输入样例:
ABC
BAC
FDXEAG
XDEFAG
输出样例:
BCA
XEDGAF

解题思路 :

(DFS) O(n)
用哈希表存储节点在前序遍历中的下标,用来计算每次DFS时子树的根节点。

AC代码 :

#include <bits/stdc++.h>
using namespace std;
const int N = 30;
unordered_map <char,int> order;

string dfs(string mid, int l, int r)
{
    string res;
    if (l > r) return res;
    if (l == r) 
    {
        res.push_back(mid[l]);
        return res;
    }
    int rootIndex = l;
    for (int i = l; i <= r; i++)
        if (order[mid[rootIndex]] > order[mid[i]])
            rootIndex = i;
    res.push_back(mid[rootIndex]);
    //从前面插入,所以先递归右子树
    res = dfs(mid, rootIndex + 1, r) + res;
    //再递归左子树
    res = dfs(mid, l, rootIndex - 1) + res;
    return res;
}

int main()
{
    string pre, mid;
    while (cin >> pre >> mid)
    {
        order.clear();
        int index = 0;
        //遍历前序序列,预处理每个节点出现的次序
        for (auto i : pre)
            order.insert({i, index++});

        string res = dfs(mid, 0, mid.size()-1);    
        cout << res << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值