Day15--二叉树--222. 完全二叉树的节点个数,110. 平衡二叉树,257. 二叉树的所有路径,404. 左叶子之和
Day15–二叉树–222. 完全二叉树的节点个数,110. 平衡二叉树,257. 二叉树的所有路径,404. 左叶子之和
222. 完全二叉树的节点个数
思路参考自:完全二叉树的节点数,你真的会算吗?
参考二:《代码随想录》:
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
这里关键在于如何去判断一个左子树或者右子树是不是满二叉树呢?
在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。
思路:完全二叉树,它的左右子树,其中至少有一颗是满二叉树。满二叉树直接根据公式计算,另一颗按照普通二叉树计算。
// 完全二叉树,它的左右子树,其中至少有一颗是满二叉树。
// 满二叉树直接根据公式计算,另一颗按照普通二叉树计算。
// 对于“不是满二叉树”的那颗子树,往下遍历的时候,也可能会有“满二叉树”的情况
// 本代码优化的速度就在于,凡是“满二叉树”就套公式。
class Solution {public int countNodes(TreeNode root) {// 其实这种就一句话的函数,是可以直接写在调用方法里的。// 多写一个方法是因为,这里的节点叫root,容易误解。叫node容易理解。return getNodeNum(root);}private int getNodeNum(TreeNode node) {// 基本上所有代码就是为了“判断是否是满二叉树”if(node==null){return 0;}// 分左右子树TreeNode left = node.left;TreeNode right = node.right;// 记录左右子树的高度// 初始化为1是因为,判断左右子树是否高度相等,是在cur本节点判断的// 如果成立,证明从本节点开始就是满二叉树,要加上本层int leftHeight = 1;int rightHeight = 1;// 统计高度while (left != null) {left = left.left;leftHeight++;}while (right != null) {right = right.right;rightHeight++;}// 如果左右子树高度相同,是一颗满二叉树,可以直接根据公式计算if (leftHeight == rightHeight) {return (int) Math.pow(2, leftHeight) - 1;}// 如果不是满二叉树,则按照普通二叉树的逻辑计算return countNodes(node.left) + countNodes(node.right) + 1;}
}
思路:
递归法:完全当成普通二叉树来算
class Solution {public int countNodes(TreeNode root) {return getNodesNum(root);}private int getNodesNum(TreeNode node) {// 节点为空,返回0if (node == null) {return 0;}// 递归左子树int leftNum = getNodesNum(node.left);// 递归右子树int rightNum = getNodesNum(node.right);// 子树节点+1(自身)->返回给上一层int curNum = leftNum + rightNum + 1;return curNum;}
}
110. 平衡二叉树
思路:
- 后序遍历法:自底向上统计
- 如果高度差大于1,返回-1做标记给上层
- 每一层算高度的时候:取左右子树之中的max,然后+1,当做是本层的高度(因为高度是自底向上算的)
// 后序遍历法:自底向上统计
class Solution {public boolean isBalanced(TreeNode root) {return getHeight(root) == -1 ? false : true;}private int getHeight(TreeNode node) {if (node == null) {return 0;}int leftHeight = getHeight(node.left);int rightHeight = getHeight(node.right);// 如果下层返回的有-1,直接返回-1给上层if (leftHeight == -1 || rightHeight == -1) {return -1;}// 如果高度差大于1,返回-1做标记给上层if (Math.abs(leftHeight - rightHeight) > 1) {return -1;}// 取左右子树之中的max,然后+1,当做是本层的高度(因为高度是自底向上算的)return Math.max(leftHeight, rightHeight) + 1;}
}
257. 二叉树的所有路径
思路:后序遍历:自下而上传递字符串,把孩子传上的字符串拼接本层,加工后传给上一层
// 后序遍历:自下而上传递字符串,把孩子传上的字符串拼接本层,加工后传给上一层
class Solution {public List<String> binaryTreePaths(TreeNode root) {return getChildrenString(root);}private List<String> getChildrenString(TreeNode node) {List<String> list = new ArrayList<>();if (node == null) {return list;}// 拼接左节点传上来的字符串if (node.left != null) {List<String> leftList = getChildrenString(node.left);// 每一个字符串,都要加上本节点的val和"->"// 然后重新加到本节点的list里,每一个node都会新一个listfor (String s : leftList) {String temp = node.val + "->" + s;list.add(temp);}}// 拼接右节点传上来的字符串if (node.right != null) {List<String> rightList = getChildrenString(node.right);for (String s : rightList) {String temp = node.val + "->" + s;list.add(temp);}}// 如果是叶子节点,直接返回本节点的val的字符串形式if (node.left == null && node.right == null) {list.add("" + node.val);}return list;}
}
404. 左叶子之和
思路:
递归遍历。要保证node.left是个叶子,才要它的值。
class Solution {public int sumOfLeftLeaves(TreeNode root) {return getLeftSum(root);}private int getLeftSum(TreeNode node) {int leftNodeSum = 0;int rightNodeSum = 0;if (node.right != null) {rightNodeSum = getLeftSum(node.right);}if (node.left != null) {leftNodeSum = getLeftSum(node.left);// 要保证node.left是个叶子,才要它的值if (node.left.left == null && node.left.right == null) {return leftNodeSum + rightNodeSum + node.left.val;}}return leftNodeSum + rightNodeSum;}
}