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;
}