目录
题目背景
L2-3 满二叉树的最小前序遍历序列
作者 PDF
单位 重庆大学
给你一个深度为 k 的满二叉树,每个节点上有一个大写字母标号,标号可能重复。你可以选择若干个(或不选择)非叶节点并将其左右孩子对换(操作顺序及次数不限),求能得到的字典序最小的前序遍历序列。
输入格式:
第一行一个整数 k (1≤k≤18),表示满二叉树的深度。
第二行一个长度为 2k−1 的仅由大写字母组成的字符串,表示该树的层序遍历序列。
输出格式:
输出一行一个字符串,表示能得到的字典序最小的前序遍历序列。
注:对于两个长度均为 2k−1 的字符串 A 和 B ,我们称字符串 A 比字符串 B “小”,如果存在 1≤i<2k 满足 A[j]=B[j] 对所有 j<i 成立,且 A[i]<B[i]。
输入样例:
3
ABBCACB
输出样例:
ABACBBC
代码长度限制
16 KB
Java (javac)
时间限制
1200 ms
内存限制
512 MB
其他编译器
时间限制
600 ms
内存限制
512 MB
栈限制
16384 KB
思路
非常好一道题!考察方面很完全,而且没想到就做不出来!想到了就很简单!!
首先复习一下
满二叉树的特性
满二叉树是特殊的二叉树,实际处理中往往直接使用数组进行存储。
在数组下标为1的地方放入根节点,然后层序放入子节点,就能直接储存整个二叉树!
而且这个二叉树有良好的特性:
- 如果一个节点 node[a] 是子节点,那么它的父节点的下标是该节点下标的一半,即:父节点是 node[a/2]
- 如果一个节点 node[a] 是父节点,那么它一定有两个子节点,左子节点是 node[a*2] ,右子节点是 node[a*2+1]。
- 最下方一层是叶子节点,起始下表是2的n-1次方。其中n是该满二叉树的层数。它们没有子节点
本题中,将字符串直接当作数据存储即可,注意前面补充一个空格填充下标为0的地方。
好的知道了这些,再复习一下
前序遍历
记一个节点是r,其左子树是L,右子树是R。
前序遍历关键是:rLR,多的不再赘述。
关键
要得到最小的字符串,r的位置无法改变,那么只能改变LR的位置,题目刚好又只能交换RL,因此我们只需要得到L子树的最小前序遍历序列,再得到R子树的最小前序遍历序列,就能比较两个序列,把小的序列放在前面,大的序列放在后面即可!
子树的最小前序遍历序列同理,找子树的左右子树最小前序遍历序列比较即可!
然后是边界处理,最深一层直接返回本身即可,无需也不能再找其子树了。注意,由于我们使用了string,不能直接返回s[index],这是一个char类型,需要特殊处理!
然后就结束力,本质感觉像递归~也像dfs~
完整代码
#include <iostream>
#include <string>
using namespace std;
long long maxx = 1;
string s;
string minn(long long startid) {
if (startid >= maxx) {
return s.substr(startid, 1);
}
string lminn = minn(startid * 2);
string rminn = minn(startid * 2 + 1);
if (lminn > rminn) {
return s[startid] + rminn + lminn;
}
return s[startid] + lminn + rminn;
}
int main() {
int n;
cin >> n;
for (int i = 1; i < n; i++) {
maxx *= 2;
}
cin >> s;
s = " " + s;
cout << minn(1);
}