二叉树第一期
刷题先刷二叉树,因为二叉树是后来其他高阶算法的基础,也是理解递归的最佳途径。
东哥这里有几句话非常经典:
- 写递归算法的关键是要明确函数的「定义」是什么,然后相信这个定义,利用这个定义推导最终结果,绝不要跳入递归的细节。
- 写树相关的算法,简单说就是,先搞清楚当前 root 节点「该做什么」以及「什么时候做」,然后根据函数定义递归调用子节点,递归调用会让孩子节点做相同的事情。
- 所谓「该做什么」就是让你想清楚写什么代码能够实现题目想要的效果,所谓「什么时候做」,就是让你思考这段代码到底应该写在前序、中序还是后序遍历的代码位置上。
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) return root;
//函数定义:给定一棵树的根节点,就会将这棵树翻转成功
//思路很简单,把左子树翻转,再把右子树翻转,这些都通过函数定义完成
//root节点要做的:把左子节点和右子节点交换
//翻转左子树
invertTree(root.left);
//翻转右子树
invertTree(root.right);
//root节点要做的
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
return root;
}
}
114. 二叉树展开为链表
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
// 定义:将以 root 为根的树拉平为链表
void flatten(TreeNode root) {
//在做二叉树的题的时候,反正他肯定要递归左子树和右子树的,而root的操作就只有前序中序和后序三种选择,
//不妨想想这root操作选选择哪一种才能解开这道题,三种选择都考虑一下!
//函数定义:给定一棵树的根节点,flatten会将其展开为一个单链表
//遵循函数定义,将左子树和右子树分别展开为单链表
//root节点要做的:把右子树变成左子树,再把右子树接在左子树的下面
// base case
if (root == null) return;
flatten(root.left);
flatten(root.right);
/**** 后序遍历位置 ****/
// 1、左右子树已经被拉平成一条链表
TreeNode left = root.left;
TreeNode right = root.right;
// 2、将左子树作为右子树
root.left = null;
root.right = left;
// 3、将原先的右子树接到当前右子树的末端
TreeNode p = root;// 注意这个地方一定是TreeNode p = root, 不能是 TreeNode p = root.right,因为递归到叶子结点的时候, root.right是空的,这个时候p就是null,再p.right就相当于null.right会空指针异常
while (p.right != null) {
p = p.right;
}
p.right = right;
}
116. 填充每个节点的下一个右侧节点指针
//函数定义:给定一棵树的root节点,将同一层所有节点连起来
//最简单的思路,root操作是连接两个子节点,然后递归,connet(root.left, root.right)
//但是这样会出错,因为一个root节点只能将自己的孩子节点连接,而不能连接不同父节点的两个相邻节点
//因此,这道题的函数定义数不能满足要求的,我们至少需要两个相邻节点来完整连接
// 主函数
Node connect(Node root) {
if (root == null) return null;
connectTwoNode(root.left, root.right);
return root;
}
// 辅助函数
void connectTwoNode(Node node1, Node node2) {
if (node1 == null || node2 == null) {
return;
}
/**** 前序遍历位置 ****/
// 将传入的两个节点连接
node1.next = node2;
// 连接相同父节点的两个子节点
connectTwoNode(node1.left, node1.right);
connectTwoNode(node2.left, node2.right);
// 连接跨越父节点的两个子节点
connectTwoNode(node1.right, node2.left);
}

浙公网安备 33010602011771号