leetcode总结 DAY14-18 二叉树

本文详细介绍了二叉树的各种遍历方法,包括前序、中序、后序遍历,以及层序遍历。同时,还涉及到了二叉树的翻转、节点深度和高度计算、完全二叉树节点数的求解,以及平衡二叉树和路径总和的问题。这些内容展示了二叉树在算法中的常见应用和解决策略。
摘要由CSDN通过智能技术生成

DAY 14 二叉树的遍历

二叉树中,大部分问题都可用递归解决

递归:

  1. 确定递归函数的参数和返回值:可以边写边添加
  2. 确定终止条件
  3. 明确函数的目的,确定单层的逻辑

144 二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

递归

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        preRecursive(res, root);
        return res;
    }
    // 输入一个根节点和一个数组,就能获得一个存有二叉树前序遍历顺序的数组
    public void preRecursive(List<Integer> res, TreeNode root){
        if(root==null){
            return;
        }
        res.add(root.val);
        preRecursive(res,root.left);
        preRecursive(res, root.right);
    }
}

94 二叉树的中序遍历

给定一个二叉树的根节点 root ,返回 它的 中序 遍历

递归

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root==null){
            return res;
        }
        inorderTraversal(root.left);
        res.add(root.val);
        inorderTraversal(root.right);
        return res;
    }
}

145 二叉树的后序遍历

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

递归

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        postRecursive(res,root);
        return res;
    }

    public void postRecursive(List<Integer> res, TreeNode root){
        if(root==null){
            return;
        }
        postRecursive(res,root.left);
        postRecursive(res,root.right);
        res.add(root.val);
    }
}

DAY 15

102 二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null){
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            List<Integer> curList = new ArrayList<>();    
            for(int i = queue.size();i>0;i--){
                root = queue.poll();
                curList.add(root.val);
                if(root.left!=null) queue.offer(root.left);
                if(root.right!=null) queue.offer(root.right);
            }
            res.add(curList);
        }
        return res;
    }

拓展:分层

双重循环实现

    int curLevelSize = 0;
    while(!queue.isEmpty()){
        curLevelSize = queue.size();
        while(curLevelSize>0){
			... ...
        }
    }

226 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

    // 输入一个根节点,就可以获得一棵翻转好的二叉树的根节点
    public TreeNode invertTree(TreeNode root) {
        if(root==null){
            return null;
        }
        TreeNode tempLeft = root.left; // 暂存左孩子
        root.left = invertTree(root.right); // 左孩子为翻转好的右子树根节点
        root.right = invertTree(tempLeft); // 右孩子为翻转好的左子树根节点
        return root;
    }

101 对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isSymmetric(root.left,root.right);
    }
    public boolean isSymmetric(TreeNode leftRoot, TreeNode rightRoot){
        if(leftRoot==null && rightRoot==null){
            return true;
        }else if(leftRoot == null || rightRoot == null){
            return false;
        }
        return leftRoot.val==rightRoot.val && isSymmetric(leftRoot.left,rightRoot.right) && isSymmetric(leftRoot.right,rightRoot.left);
    }
}

DAY 16

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数后者节点数(取决于高度从0开始还是从1开始)

104 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

    public int maxDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        return 1 + Math.max(maxDepth(root.left),maxDepth(root.right));
    }

559 N 叉树的最大深度

给定一个 N 叉树,找到其最大深度。

最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。

N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。

    public int maxDepth(Node root) {
        if(root == null){
            return 0;
        }
        int res = 1;
        for(int i=0;i<root.children.size();i++){
          int childDeepth = maxDepth(root.children.get(i));
          res = Math.max(res, 1+childDeepth);  
        }
        return res;
    }

111 二叉树的最小深度

给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

**说明:**叶子节点是指没有子节点的节点。

解题思路:

题目中说的是:最小深度是从根节点到最近叶子节点的最短路径上的节点数量。注意是叶子节点,左右孩子都为空的节点才是叶子节点!!!仅左或右孩子为空的不是叶子节点,不是递归停止的条件

image-20221123114055740

归结束条件:

  • 当 root 节点左右孩子都为空时(叶子节点),返回 1
  • 当 root 节点左右孩子有一个为空时,返回不为空的孩子节点的深度
  • 当 root 节点左右孩子都不为空时,返回左右孩子较小深度的节点值
    public int minDepth(TreeNode root) {
        if(root == null){
            return 0;
        }else if(root.left==null && root.right==null){ // 找到叶子结点啦
            return 1;
        }
        // left 或 right 有一个不为空
        int leftMin = minDepth(root.left);
        int rightMin = minDepth(root.right);
        // return root.left==null? 1+rightMin : (root.right==null? 1+leftMin : 1+Math.min(leftMin,rightMin)); 
        // 简化 : 当左或右孩子为空时,leftMin和RightMin 一个为0,一个不为0,任何数加0值变,因此此时的结果为 1+leftMin+rightMin
        return root.left==null || root.right==null ? 1+leftMin+rightMin : 1+Math.min(leftMin,rightMin);
    }

222 完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

方法一:递归统计

    public int countNodes(TreeNode root) {
        if(root==null){
            return 0;
        }
        return 1+countNodes(root.left)+countNodes(root.right);
    }

方法二:

如果去判断一个左子树或者右子树是不是满二叉树呢?

在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树


DAY 17

110 平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

    public boolean isBalanced(TreeNode root) {
        if(root==null){
            return true;
        }
        int hightL = height(root.left);
        int heightR = height(root.right);
        return Math.abs(hightL-heightR)<=1 && isBalanced(root.left) && isBalanced(root.right);
    }
    public int height(TreeNode root){
        if(root==null){
            return 0;
        }
        return 1+Math.max(height(root.left),height(root.right));
    }

257 二叉树的所有路径

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

叶子节点 是指没有子节点的节点。

回溯

    List<String> res = new ArrayList<>();
    public List<String> binaryTreePaths(TreeNode root) {
        treePath(root, new ArrayList<>());
        return res;
    }
    public void treePath(TreeNode root, List<String> list){
        // 1. root为空:直接return
        if(root==null){
            return;
        }
        // 2. root左右孩子均空:找到叶子结点,将这条路径加入
        if(root.left==null && root.right==null){
            list.add(String.valueOf(root.val));
            StringBuilder sb = new StringBuilder();
            for(int i=0;i<list.size();i++){
                sb.append(list.get(i));
            }
            res.add(sb.toString());
            list.remove(list.size()-1);
        }
        // 3. root左或者右有一个不空:加入不空的
        list.add(root.val+"->");
        treePath(root.left,list);
        treePath(root.right,list);
        list.remove(list.size()-1);
    }

404. 左叶子之和

给定二叉树的根节点 root ,返回所有左叶子之和。

    public int sumOfLeftLeaves(TreeNode root) {
        if(root==null){
            return 0;
        }
        int sum = 0;
        // 左孩子
        TreeNode leftRoot = root.left;
        if(leftRoot!=null){
            // 1) 左孩子是叶子结点
            if(leftRoot.right==null && leftRoot.left==null){
                sum += leftRoot.val;
            }else{
                // 2) 左孩子是棵树,返回左子树所有左叶子之和
                sum += sumOfLeftLeaves(leftRoot);
            }
        }
        // 右孩子
        TreeNode rightRoot = root.right;
        if(rightRoot!=null){
            // 1) 右孩子是叶子结点
            if(rightRoot.right==null && rightRoot.left==null){
                sum += 0;
            }else{
                // 2) 右孩子不是叶子结点,是棵树,返回右子树所有左叶子之和
                sum += sumOfLeftLeaves(rightRoot);
            }
        }
        // 当前结点: 是叶子节点返回0;  不是叶子结点,返回以当前节点为根的树的所有左叶子之和
        return leftRoot==null && rightRoot==null ? 0 : sum;
    }

DAY 18

513 找树左下角的值

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

迭代法

过于麻烦了

    public int findBottomLeftValue(TreeNode root) {
        Deque<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        TreeNode nextLevel = root; // 不断移动,用于找下一层中最左边结点
        TreeNode leftNode = root; // 记录找到的最左边结点
        while(!queue.isEmpty()){
           TreeNode curNode = queue.poll();
           if(curNode == nextLevel){
               if(curNode.left!=null){
                   nextLevel = curNode.left;
                   leftNode = curNode.left;
               }else if(curNode.right!=null){
                   nextLevel = curNode.right;
                   leftNode = curNode.right;
               } else nextLevel = queue.peek();
           }
           if(curNode.left!=null) queue.offer(curNode.left);
           if(curNode.right!=null) queue.offer(curNode.right);
        }
        return leftNode.val;
    }

层序遍历分层

    public int findBottomLeftValue(TreeNode root) {
        Deque<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        TreeNode leftNode = root;
        int curLevelSize = 0;
        while(!queue.isEmpty()){
            curLevelSize = queue.size();
            leftNode = queue.peek();
            while(curLevelSize>0){
                TreeNode curNode = queue.poll();
                if(curNode.left!=null) queue.offer(curNode.left);
                if(curNode.right!=null) queue.offer(curNode.right);
                curLevelSize--;
            }
        }
        return leftNode.val;
    }

递归法

    public int findBottomLeftValue(TreeNode root) {
        // 错误: dfs(root,0); // 由于level默认为0,若树从0开始算起,则仅一个根节点的情况无法包含进去
        dfs(root,1);
        return leftVal;
    }
	int level; // 已遍历树中最左下角结点所在层数
    // TreeNode node = new TreeNode(); // 已遍历树中最左下角结点
	// 优化
    int leftVal; // 已遍历树中最左下角结点的值
	
	// 输入一个节点就可以找到 以当前结点为根的树中最左下角结点,并与已经找过的子树最左下角结点作比较,保留深度更大的
    public void dfs(TreeNode root, int curLevel){
        if(root==null){
            return;
        }
        // 当前节点是叶子节点,且当前结点所在层数大于node结点所在层数 (不可取等,因为前序遍历,同一层中当前节点左边的结点已经判断过了)
        if(root.left==null && root.right==null && curLevel>level){
            leftVal = root.val;
            level = curLevel;
        }
        dfs(root.left,curLevel+1);
        dfs(root.right,curLevel+1);
    }

112 路径总和

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false

叶子节点 是指没有子节点的节点。

    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; // wow
        }
        return hasPathSum(root.left, targetSum) || hasPathSum(root.right,targetSum);
    }

递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

  • 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(113.路径总和ii)
  • 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。
  • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。

113 路径总和 II

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        pathFind(root,targetSum);
        return res;
    }
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    public void pathFind(TreeNode root, int targetSum){
        if(root==null){
            return;
        }
        path.add(root.val);

        targetSum -= root.val;
        if(targetSum==0 && root.left==null && root.right==null){
            res.add(new ArrayList<Integer>(path));
            return;
        }

        if(root.left!=null){
            pathFind(root.left,targetSum);
            path.remove(path.size()-1);
        }
        if(root.right!=null){
            pathFind(root.right,targetSum);
            path.remove(path.size()-1);
        }

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值