发布时间:2024-06-20 11:01
上述的结果是:
1 2 4 7 11 13 14 15 16 12 10 6 3
空间限制是 O ( h ) O(h) O(h),时间限制是 O ( N ) O(N) O(N), h h h是树的高度, N N N是节点的个数。
需要的节点分为三种:
根据节点的特性,在前序遍历的时候,同一层中最先访问到的节点是左边界节点;最后访问到的是右边界节点。根据这个特性,可以计算左右边界。
如果一个节点没有左右孩子,而且不是左右边界,则该节点一定是底层叶子节点。
问题的难点在于,怎样在 O ( h ) O(h) O(h)的空间和 O ( N ) O(N) O(N)的时间中计算左右边界;因为底层叶子节点求解,在叶子节点中排除左右边界即可。
我们建立一个数组edgeNodes[H][2]
,H
是树的高度。edgeNodes[h][0]
表示这层的左边界,edgeNodes[h][0]
表示右边界。之后进行前序遍历,当每次访问到第一个节点的时候,就是这层的左边界,此时存储到edgeNodes[h][0]
中;同样的,只要遍历到某一层的节点,而且不是左边界节点,就用该节点更新edgeNodes[h][1]
中,因为右边界是最后访问到的。注意边界条件,二叉树退化成线性的情况,此时不论左右孩子,都看成是左边界(当然可以看成右边界,但是不要重复)。
给出求解代码:
#include
#include
#include
#include
#include
struct Node {
int val;
std::shared_ptr<Node> left{nullptr}, right{nullptr};
Node (int n = 0): val(n), left(nullptr), right(nullptr) {}
};
std::vector<std::array<std::shared_ptr<Node>, 2>> edgeNodes; // 左右边界点
std::vector<std::shared_ptr<Node>> leaves; // 不在左右边界的叶子节点
// 计算树高
int GetTreeHeight(const std::shared_ptr<Node>& root) {
if (root == nullptr) {
return 0;
}
return std::max(GetTreeHeight(root->left) + 1, GetTreeHeight(root->right) + 1);
}
// 前序创建二叉树
std::shared_ptr<Node> CreateTreePreOrder() {
int n;
std::cin >> n;
if (n <= 0) {
return nullptr;
}
auto root = std::make_shared<Node>(n);
root->left = CreateTreePreOrder();
root->right = CreateTreePreOrder();
return root;
}
// 设置边界
void SetEdges(const std::shared_ptr<Node>& root, int h) {
if (root == nullptr) {
return;
}
if (edgeNodes[h][0] == nullptr) { // 先序遍历,同层左边界总是最先被访问到
edgeNodes[h][0] = root;
}
if (edgeNodes[h][0] != nullptr && root != edgeNodes[h][0]) { // 先序遍历,同层右边界总是最后访问到
edgeNodes[h][1] = root;
}
SetEdges(root->left, h + 1);
SetEdges(root->right, h + 1);
}
// 设置叶子节点,不在左右边界的叶子
void SetLeaves(const std::shared_ptr<Node>& root, int h) {
if (root == nullptr) {
return;
}
if (root->left == nullptr && root->right == nullptr && edgeNodes[h][0] != root && edgeNodes[h][1] != root) {
leaves.push_back(root);
}
SetLeaves(root->left, h + 1);
SetLeaves(root->right, h +1);
}
void Print() {
int N = edgeNodes.size();
// std::cout << \"left edges: \";
for (int i = 0; i < N; ++i) {
if (edgeNodes[i][0] != nullptr) {
std::cout << edgeNodes[i][0]->val << \" \";
}
}
// std::cout << \"\\nleaves: \";
for (const auto &p: leaves) {
std::cout << p->val << \" \";
}
// std::cout << \"\\nright edges: \";
for (int i = N - 1; i >= 0; --i) {
if (edgeNodes[i][1] != nullptr) {
std::cout << edgeNodes[i][1]->val << \" \";
}
}
}
int main() {
// 1 2 -1 4 7 -1 -1 8 -1 11 13 -1 -1 14 -1 -1 3 5 9 12 15 -1 -1 16 -1 -1 -1 10 -1 -1 6 -1 -1
auto root = CreateTreePreOrder();
edgeNodes.resize(GetTreeHeight(root)); // 分配空间
SetEdges(root, 0);
SetLeaves(root, 0);
Print();
return 0;
}
程序输出:
left edges: 1 2 4 7 11 13
leaves: 14 15
right edges: 16 12 10 6 3