对称二叉树
题目:101
-
迭代:通过队列来判断根节点的左子树和右子树的内侧和外侧是否相等
-
把要比较的对称节点放在队列的相邻位置
-
递归
-
private boolean compare(TreeNode left, TreeNode right) { if (left == null && right != null) { return false; } if (left != null && right == null) { return false; } if (left == null && right == null) { return true; } if (left.val != right.val) { return false; } //以上四种情况是确认返回条件 boolean compareOutside = compare(left.left, right.right);//二叉树外侧是否相等 boolean compareInside = compare(left.right, right.left);//二叉树内测是否相等 return compareOutside && compareInside;}
完全二叉树的节点个数
题目:222
- 简单来说,我又想到了万能的按层遍历
- 但是,这是完全二叉树,所以最好考虑一下完全二叉树的性质
- 完全二叉树只有两种情况
- 情况一:就是满二叉树,对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
- 情况二:最后一层叶子节点没有满。 对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
- 就,就算只有一个节点,也算满二叉树
return countNodes(root.left) + countNodes(root.right) + 1;//这个+1就是加的“当前满二叉树”的上一个节点
二叉树的最大深度
- 是的,虽然上一节里录入过这道题,但是当时只涉及层序遍历,这里就要深入考虑一下别的了
- 先区分一下高度和深度吧
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始) 前序遍历
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始) 后序遍历
- 顺便,记一下求深度的递归法,感觉也是一个常用的方法
public int maxDepth(TreeNode root) {//参数就是传入树的根节点,返回就返回这棵树的深度,
//所以返回值为int类型。
if (root == null) {
return 0;//如果为空节点的话,就返回0,表示高度为0。
}
int leftDepth = maxDepth(root.left);//先求它的左子树的深度
int rightDepth = maxDepth(root.right);//再求右子树的深度,
return Math.max(leftDepth, rightDepth) + 1;//最后取左右深度最大的数值 再+1
//(加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。
}
二叉树的最小深度
- 求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。
- 所以递归方法中有所不同
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if (root.left == null) {
return rightDepth + 1;
}
if (root.right == null) {
return leftDepth + 1;
}
// 左右结点都不为null
return Math.min(leftDepth, rightDepth) + 1;
平衡二叉树
题目:110
- 递归三步
- 递归函数的参数和返回值:
- 参数:当前传入节点。
- 返回值:以当前传入节点为根节点的树的高度。
- 终止条件:节点为空
- 单层递归逻辑:分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。感觉就是在求二叉树最大深度的代码里加几个判定条件
- 这里的递归函数是直接把该做的都做了,不是仅仅用来求高度,毕竟高度求都求了,顺便再比较一下高度差吧
二叉树的所有路径
题目:257
- 我不喜欢的递归,回溯......
- 从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
- 递归函数的参数和返回值:要传入根节点,记录每一条路径的path,和存放结果集的result,这里递归不需要返回值,因为直接把结果放在result里了
- 终止条件:遇到叶子节点,当前节点不为空,但是它的左右节点为空
- 单层递归逻辑:当遇到叶子节点的时候,要把这条路径记录下来。如果没有遇到,则继续沿着路径走。以及,递归和回溯是一起进行的,所谓回溯其实就可以认为是递归+剪枝,所以两者要放在一起,如下。
if (root.left != null) { // 左
traversal(root.left, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
- 看题目要求,返回的是字符串的集合,但是字符串又是由数字和"->"组成,所以弄两个List,一个记录路径字符串,一个记录节点值。然后路径字符串由记录节点值的List拼接起来
paths.add(root.val);// 前序遍历,中
if (root.left == null && root.right == null) {
// 输出
StringBuilder sb = new StringBuilder();// StringBuilder用来拼接字符串,速度更快
for (int i = 0; i < paths.size() - 1; i++) {
sb.append(paths.get(i)).append("->");
}
sb.append(paths.get(paths.size() - 1));// 记录最后一个节点
res.add(sb.toString());// 收集一个路径
return;
}