L2-3 满二叉树的最小前序遍历序列 【详细题解】

目录

题目背景

输入格式:

输出格式:

输入样例:

输出样例:

思路

满二叉树的特性

前序遍历

关键

完整代码


题目背景

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值