222. 完全二叉树的节点个数
普通二叉树解法(用后序)
class Solution {
public int countNodes(TreeNode root) {
//终止条件
if(root==null) return 0;
int left=countNodes(root.left);
int right=countNodes(root.right);
int count=left+right+1;
return count;
}
}
完全二叉树解法
满二叉树节点数量:2的深度次方-1
class Solution {
public int countNodes(TreeNode root) {
if(root == null) {
return 0;
}
int leftDepth = getDepth(root.left);
int rightDepth = getDepth(root.right);
if (leftDepth == rightDepth) {// 左子树是满二叉树
// 2^leftDepth其实是 (2^leftDepth - 1) + 1 ,左子树 + 根结点
return (1 << leftDepth) + countNodes(root.right);
} else {// 右子树是满二叉树
return (1 << rightDepth) + countNodes(root.left);
}
}
private int getDepth(TreeNode root) {
int depth = 0;
while (root != null) {
root = root.left;
depth++;
}
return depth;
}
}
110. 平衡二叉树
二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数
因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)
class Solution {
public boolean isBalanced(TreeNode root) {
return getBalanced(root)!=-1;
}
public int getBalanced(TreeNode root){
if(root==null) return 0;
int leftDepth=getBalanced(root.left);
if(leftDepth==-1){
return -1;
}
int rightDepth=getBalanced(root.right);
if(rightDepth==-1){
return -1;
}
if(Math.abs(leftDepth-rightDepth)>1){
return -1;
}
return Math.max(leftDepth,rightDepth)+1;
}
}
257. 二叉树的所有路径
这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
在这道题目中涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一一个路径在进入另一个路径。
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
if (root == null) {
return res;
}
List<Integer> paths = new ArrayList<>();
traverse(root, paths, res);
return res;
}
//path存放单条路径,res存放结果
public void traverse(TreeNode root,List<Integer> paths, List<String> res){
paths.add(root.val);
//左右孩子均为空说明遍历到了叶子节点,就是终止条件
//因为遍历到叶子节点就结束所以把中的加入path写入到结束条件中
if (root.left == null && root.right == null) {
// 输出
StringBuilder sb = new 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;
}
//单层递归
if (root.left != null) {
traverse(root.left, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
if (root.right != null) {
traverse(root.right, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
}
}
404. 左叶子之和
本题中的左叶子
节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点
本题与之前递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。的区别是通过父节点来判断子节点是不是想要收集的元素
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root==null) return 0;
//判断是否为叶子节点,但是不知道这个叶子节点是不是想要收集的左叶子
if(root.left==null&&root.right==null) return 0;
//遍历左子树
int leftNums=sumOfLeftLeaves(root.left);
//遍历右子树
int rightNums=sumOfLeftLeaves(root.right);
if(root.left!=null&&root.left.left==null&&root.left.right==null){
leftNums=root.left.val;
}
//中
int sum=leftNums+rightNums;
return sum;
}
}
513. 找树左下角的值
分析一下题目:在树的最后一行找到最左边的值。最靠左侧的节点不一定是左节点
深度最大的叶子节点一定是最后一行。
可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
class Solution {
//记录二叉树中的最大深度
int maxDepth=Integer.MIN_VALUE;
//记录结果节点,每更新深度都更新节点,这样就可以记录深度最大的节点
int res=0;
public int findBottomLeftValue(TreeNode root) {
res = root.val;
findLeftValue(root,0);
return res;
}
//depth是遍历当前深度
public void findLeftValue(TreeNode root,int depth){
if(root==null) return ;
//终止条件
if(root.left==null&&root.right==null){
if(depth>maxDepth){
maxDepth=depth;
res=root.val;
}
}
//左
depth++;
findLeftValue(root.left,depth);
depth--;//回溯
//右
depth++;
findLeftValue(root.right,depth);
depth--;
}
}
112. 路径总和
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false;
}
targetSum -= root.val;
// 叶子结点
if (root.left == null && root.right == null) {
return targetSum == 0;
}
if (root.left != null) {
boolean left = hasPathSum(root.left, targetSum);
if (left) {// 已经找到
return true;
}
}
if (root.right != null) {
boolean right = hasPathSum(root.right, targetSum);
if (right) {// 已经找到
return true;
}
}
return false;
}
}