问题涉及有:
- 遍历
- 翻转
- 子树
写二叉树的算法题,都是基于递归框架的。我们先要搞清楚 root 节点它自己要做什么,然后根据题目要求选择使用前序,中序,后续的递归框架。
二元树的结点定义如下:
struct SBinaryTreeNode // a node of the binary tree
{
int m_nValue; // value of node
SBinaryTreeNode *m_pLeft; // left child of node
SBinaryTreeNode *m_pRight; // right child of node
};
二叉树递归框架
/* 二叉树遍历框架 */
void traverse(TreeNode root) {
// 前序遍历
traverse(root.left)
// 中序遍历
traverse(root.right)
// 后序遍历
}
输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。用递归和循环两种方法完成树的镜像转换。例
如输入:
8
/ \
6 10
/\ / \
5 7 9 11
输出:
8
/ \
10 6
/\ /\
11 9 7 5
思路:二叉树翻转 , 把二叉树上的每一个节点的左右子节点进行交换
// 将整棵树的节点翻转
TreeNode invertTree(TreeNode root) {
// base case
if (root == null) {
return null;
}
/**** 前序遍历位置 ****/
// root 节点需要交换它的左右子节点
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
// 让左右子节点继续翻转它们的子节点
invertTree(root.left);
invertTree(root.right);
return root;
}
难度:中等
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点
,只调整指针的指向。
10
/ \
6 14
/\ / \
4 8 12 16
转换成双向链表 4=6=8=10=12=14=16
分析:题目要求不能创建任何节点,也就是只能调整各个节点的指向 思路一:
设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分
输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。
分析:求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题至少有两个变种。
TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// base case
if (root == null) return null;
if (root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
// 情况 1 :p, q 在 root 为根的树中
if (left != null && right != null) {
return root;
}
// 情况 2 :p, q 不在 在 root 为根的树中
if (left == null && right == null) {
return null;
}
// 情况 3 : p, q 只有1个在root 为根的树中
return left == null ? right : left;
}
两个节点的距离的定义是 这两个节点间边的个数,比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度。
题目:输入一个整数和一棵二元树。从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。打印出和与输入整数相等的所有路径。
例如 输入整数22和如下二元树
10
/ \
5 12
/\
4 7
则打印出两条路径:10, 12
和 10, 5, 7
。
- 累加当前节点,累加和大于给定值
- 不为叶节点,左子树入栈
复杂度如果是O(n2)则不得分。