[LeetCode] Boundary of Binary Tree 二叉树的边界
Given a binary tree, return the values of its boundary in anti-clockwise direction starting from root. Boundary includes left boundary, leaves, and right boundary in order without duplicate nodes.
Left boundary is defined as the path from root to the left-most node. Right boundary is defined as the path from root to the right-most node. If the root doesn't have left subtree or right subtree, then the root itself is left boundary or right boundary. Note this definition only applies to the input binary tree, and not applies to any subtrees.
The left-most node is defined as a leaf node you could reach when you always firstly travel to the left subtree if exists. If not, travel to the right subtree. Repeat until you reach a leaf node.
The right-most node is also defined by the same way with left and right exchanged.
Example 1
Input:
1
\
2
/ \
3 4 Ouput:
[1, 3, 4, 2] Explanation:
The root doesn't have left subtree, so the root itself is left boundary.
The leaves are node 3 and 4.
The right boundary are node 1,2,4. Note the anti-clockwise direction means you should output reversed right boundary.
So order them in anti-clockwise without duplicates and we have [1,3,4,2].
Example 2
Input:
____1_____
/ \
2 3
/ \ /
4 5 6
/ \ / \
7 8 9 10 Ouput:
[1,2,4,7,8,9,10,6,3] Explanation:
The left boundary are node 1,2,4. (4 is the left-most node according to definition)
The leaves are node 4,7,8,9,10.
The right boundary are node 1,3,6,10. (10 is the right-most node).
So order them in anti-clockwise without duplicate nodes we have [1,2,4,7,8,9,10,6,3].
这道题给了一棵二叉树,让我们以逆时针的顺序来输出树的边界,按顺序分别为左边界,叶结点和右边界。题目中给的例子也很清晰的明白哪些算是边界上的结点。那么最直接的方法就是分别按顺序求出左边界结点,叶结点,和右边界结点。那么如何求的,对于树的操作肯定是用递归最简洁啊,所以可以写分别三个递归函数来分别求左边界结点,叶结点,和右边界结点。首先要处理根结点的情况,当根结点没有左右子结点时,其也是一个叶结点,那么一开始就将其加入结果 res 中,那么再计算叶结点的时候又会再加入一次,这样不对。所以判断如果根结点至少有一个子结点,才提前将其加入结果 res 中。然后再来看求左边界结点的函数,如果当前结点不存在,或者没有子结点,直接返回。否则就把当前结点值加入结果 res 中,然后看如果左子结点存在,就对其调用递归函数,反之如果左子结点不存在,那么对右子结点调用递归函数。而对于求右边界结点的函数就反过来了,如果右子结点存在,就对其调用递归函数,反之如果右子结点不存在,就对左子结点调用递归函数,注意在调用递归函数之后才将结点值加入结果 res,因为是需要按逆时针的顺序输出。最后就来看求叶结点的函数,没什么可说的,就是看没有子结点存在了就加入结果 res,然后对左右子结点分别调用递归即可,参见代码如下:
解法一:
class Solution {
public:
vector<int> boundaryOfBinaryTree(TreeNode* root) {
if (!root) return {};
vector<int> res;
if (root->left || root->right) res.push_back(root->val);
leftBoundary(root->left, res);
leaves(root, res);
rightBoundary(root->right, res);
return res;
}
void leftBoundary(TreeNode* node, vector<int>& res) {
if (!node || (!node->left && !node->right)) return;
res.push_back(node->val);
if (!node->left) leftBoundary(node->right, res);
else leftBoundary(node->left, res);
}
void rightBoundary(TreeNode* node, vector<int>& res) {
if (!node || (!node->left && !node->right)) return;
if (!node->right) rightBoundary(node->left, res);
else rightBoundary(node->right, res);
res.push_back(node->val);
}
void leaves(TreeNode* node, vector<int>& res) {
if (!node) return;
if (!node->left && !node->right) {
res.push_back(node->val);
}
leaves(node->left, res);
leaves(node->right, res);
}
};
下面这种方法把上面三种不同的递归揉合到了一个递归中,并用 bool 型变量来标记当前是求左边界结点还是求右边界结点,同时还有加入叶结点到结果 res 中的功能。如果左边界标记为 true,那么将结点值加入结果 res 中,下面就是调用对左右结点调用递归函数了。根据上面的解题思路可以知道,如果是求左边界结点,优先调用左子结点,当左子结点不存在时再调右子结点,而对于求右边界结点,优先调用右子结点,当右子结点不存在时再调用左子结点。综上考虑,在对左子结点调用递归函数时,左边界标识设为 leftbd && node->left,而对右子结点调用递归的左边界标识设为 leftbd && !node->left,这样左子结点存在就会被优先调用。而右边界结点的情况就正好相反,调用左子结点的右边界标识为 rightbd && !node->right, 调用右子结点的右边界标识为 rightbd && node->right,这样就保证了右子结点存在就会被优先调用,参见代码如下:
解法二:
class Solution {
public:
vector<int> boundaryOfBinaryTree(TreeNode* root) {
if (!root) return {};
vector<int> res{root->val};
helper(root->left, true, false, res);
helper(root->right, false, true, res);
return res;
}
void helper(TreeNode* node, bool leftbd, bool rightbd, vector<int>& res) {
if (!node) return;
if (!node->left && !node->right) {
res.push_back(node->val);
return;
}
if (leftbd) res.push_back(node->val);
helper(node->left, leftbd && node->left, rightbd && !node->right, res);
helper(node->right, leftbd && !node->left, rightbd && node->right, res);
if (rightbd) res.push_back(node->val);
}
};
下面这种解法实际上时解法一的迭代形式,整体思路基本一样,只是没有再用递归的写法,而是均采用 while 的迭代写法,注意在求右边界结点时迭代写法很难直接写出逆时针的顺序,我们可以先反过来保存,最后再调个顺序即可,参见代码如下:
解法三:
class Solution {
public:
vector<int> boundaryOfBinaryTree(TreeNode* root) {
if (!root) return {};
vector<int> res, right;
TreeNode *l = root->left, *r = root->right, *p = root;
if (root->left || root->right) res.push_back(root->val);
while (l && (l->left || l->right)) {
res.push_back(l->val);
if (l->left) l = l->left;
else l = l->right;
}
stack<TreeNode*> st;
while (p || !st.empty()) {
if (p) {
st.push(p);
if (!p->left && !p->right) res.push_back(p->val);
p = p->left;
} else {
p = st.top(); st.pop();
p = p->right;
}
}
while (r && (r->left || r->right)) {
right.push_back(r->val);
if (r->right) r = r->right;
else r = r->left;
}
res.insert(res.end(), right.rbegin(), right.rend());
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/545
类似题目:
参考资料:
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Boundary of Binary Tree 二叉树的边界的更多相关文章
- [LeetCode] 545. Boundary of Binary Tree 二叉树的边界
Given a binary tree, return the values of its boundary in anti-clockwise direction starting from roo ...
- 545. Boundary of Binary Tree二叉树的边界
[抄题]: Given a binary tree, return the values of its boundary in anti-clockwise direction starting fr ...
- Leetcode 110 Balanced Binary Tree 二叉树
判断一棵树是否是平衡树,即左右子树的深度相差不超过1. 我们可以回顾下depth函数其实是Leetcode 104 Maximum Depth of Binary Tree 二叉树 /** * Def ...
- LeetCode - Boundary of Binary Tree
Given a binary tree, return the values of its boundary in anti-clockwise direction starting from roo ...
- [LeetCode] Diameter of Binary Tree 二叉树的直径
Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a b ...
- [LeetCode] 110. Balanced Binary Tree ☆(二叉树是否平衡)
Balanced Binary Tree [数据结构和算法]全面剖析树的各类遍历方法 描述 解析 递归分别判断每个节点的左右子树 该题是Easy的原因是该题可以很容易的想到时间复杂度为O(n^2)的方 ...
- Leetcode 226 Invert Binary Tree 二叉树
交换左右叶子节点 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * ...
- (二叉树 递归) leetcode 105. Construct Binary Tree from Preorder and Inorder Traversal
Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...
- (二叉树 递归) leetcode 106. Construct Binary Tree from Inorder and Postorder Traversal
Given inorder and postorder traversal of a tree, construct the binary tree. Note:You may assume that ...
随机推荐
- java并发编程基础 --- 7章节 java中的13个原子操作类
当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量 i=1,A线程更新 i+1,B线程也更新 I+1,经过两个线程的操作之后可能 I不等于3,而是等于2.因为A和B线程更 ...
- Wannafly交流赛1(施工中)
A.有理数 签到题:直接用floor函数就行了,详细看代码 #define debug #include<stdio.h> #include<math.h> #include& ...
- [BZOJ 2064]分裂
2064: 分裂 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 572 Solved: 352[Submit][Status][Discuss] De ...
- 201621123060 《Java程序设计》第五周学习总结
1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 继承.多态.抽象类与接口 1.2 尝试使用思维导图将这些关键词组织起来.注:思维导图一般不需要出现过多的字. 2. 书面作业 作 ...
- 【微软大法好】VS Tools for AI全攻略
大家都知道微软在Connect();17大会上发布了VS Tools for AI,旨在提升Visual Studio和VSCode对日益增长的深度学习需求的体验.看了一圈,网上似乎没有一个完整的中文 ...
- java希尔排序
java希尔排序 1.基本思想: 希尔排序也成为"缩小增量排序",其基本原理是,现将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少,然后对各个子序列分别进行直接插 ...
- 新概念英语(1-97)A Small Blue Case
Lesson 97 A small blue case 一只蓝色的小箱子 Listen to the tape then answer this question. Does Mr. Hall get ...
- Docker学习笔记 - Docker容器的日志
docker logs [-f] [-t] [--tail] 容器名 -f -t --tail="all" 无参数:返回所有日志 -f 一直跟踪变化并返回 -t 带时间戳返 ...
- GIT入门笔记(7)- 修改文件并向版本库提交
1.修改文件vi readme.txt git status 发现被修改的文件列表git diff readme.txt 2.git add readme.txt git status --注意gi ...
- Beautifulsoup4
kindEditor 1 官网:http://kindeditor.net/doc.php 2 文件夹说明: ├── asp asp示例 ├── asp.net asp.net示例 ├── attac ...