算法训练营Day14

news2024/12/23 22:25:15

#Java #二叉树层次遍历 #反转二叉树

开源学习资料

二叉树的层次遍历:力扣题目链接

二叉树的层次遍历很好理解:

就是从根结点一层一层地往下遍历(同一层,从左到右):

迭代的方式很好理解:就是依次入队出队。

但是判断条件怎么写?

最需要解决的就是,要把节点依次入队,那要怎么记录这些节点,防止它们丢失。

第一步把根节点先入队,这时候要想让它的左孩子和右孩子入队(如上图),就要在A出队的时候,记录它。

关键的就是在一个节点出队的时候,记录该节点,就能找到它的左右孩子。

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null){
            return res;
        }
    //模拟成一个队列
    //从根节点开始,依次入队(从左到右)
    Queue<TreeNode> queue = new LinkedList<>(); //创建一个队列
  
    //根节点先入队
    queue.offer(root);
    while(!queue.isEmpty()){
        int len = queue.size();
          List<Integer> list  = new ArrayList<>();
        while(len>0){
        //记录出队的节点
        TreeNode node = queue.poll();
        list.add(node.val);
        if(node.left!=null){
            //左孩子入队
            queue.offer(node.left);
        }
        if(node.right!=null){
            //右孩子入队
            queue.offer(node.right);
        }
        len--;
    }
    res.add(list);
    }
    return res;
    }
}

用两个while循环,主要是为了满足结果形式,保证每个结果都保存在一个新的集合中。

不然就是这样的(结果不能反映出是层次遍历)

先使用DFS迭代遍历练习以下题目:

二叉树的层序遍历II:力扣题目链接

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

/**
 * 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;
 *     }
 * }
 */
 class Solution {
     List<List<Integer>> res = new LinkedList<>();
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
       Queue<TreeNode> que = new LinkedList<>();
       if(root == null){
           return res;
       }
       //先把根节点入队
       que.offer(root);
       while(!que.isEmpty()){
           List<Integer> list = new ArrayList<>();
           int size = que.size();
           //每一层入队出队
           for(int i =0;i<size;i++){
               TreeNode node = que.poll();
               list.add(node.val);
               if(node.left != null){
                   que.offer(node.left);
               }
               if(node.right != null){
                   que.offer(node.right);
               }
           }
           res.add(0,list);
       }
       return res;
        
    }
}

思路相同,只是用了链表的翻转。

二叉树的右视图:力扣题目链接

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Deque<TreeNode> que = new LinkedList<>();

        if (root == null) {
            return list;
        }

        que.offer(root);
        while (!que.isEmpty()) {
            int levelSize = que.size();

            for (int i = 0; i < levelSize; i++) {
                TreeNode node = que.poll();

                if (node.left != null) {
                    que.offer(node.left);
                }
                if (node.right != null) {
                    que.offer(node.right);
                }
                //就多一步:
                //只要最右边的:
                if (i == levelSize - 1) {
                    list.add(node.val);
                }
            }
        }

        return list;
    }
}

 这道题就关键的一步:只把最右边的放到结果中!

二叉树的层平均值:力扣题目链接

给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。 

/**
 * 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;
 *     }
 * }
 */
class Solution {

    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> list = new ArrayList<>();
    Queue<TreeNode> que = new LinkedList<>();
    if(root==null){
        return list;
    }
    que.offer(root);
    while(!que.isEmpty()){
        int size = que.size();
        Double sum =0.0;
        for(int i =0 ;i<size;i++){
            TreeNode node = que.poll();
            sum+=node.val;
            if(node.left!=null){
                que.offer(node.left);
            }
            if(node.right!=null){
                que.offer(node.right);
            }
        }
        Double average = sum/size;
        list.add(average);
    }
    return list;
    }
}

一层一层计算 !

 N叉树的层序遍历:力扣题目链接

给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        if (root == null) {
            return new ArrayList<List<Integer>>();
        }

        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        Queue<Node> queue = new ArrayDeque<Node>();
        queue.offer(root);

        while (!queue.isEmpty()) {
            int cnt = queue.size();
            List<Integer> level = new ArrayList<Integer>();
            for (int i = 0; i < cnt; ++i) {
                Node cur = queue.poll();
                level.add(cur.val);
                for (Node child : cur.children) {
                    queue.offer(child);
                }
            }
            ans.add(level);
        }

        return ans;
    }
}

在每个树行中找最大值:力扣题目链接

您需要在二叉树的每一行中找到最大的值。

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public List<Integer> largestValues(TreeNode root) {
        if(root == null){
            return Collections.emptyList();
        }
        List<Integer> result = new ArrayList();
        Queue<TreeNode> queue = new LinkedList();
        queue.offer(root);
        while(!queue.isEmpty()){
            int max = Integer.MIN_VALUE;
            for(int i = queue.size(); i > 0; i--){
               TreeNode node = queue.poll();
               max = Math.max(max, node.val);
               if(node.left != null) queue.offer(node.left);
               if(node.right != null) queue.offer(node.right);
            }
            result.add(max);
        }
        return result;
    }
}

二叉树的最大深度:力扣题目链接

给定一个二叉树 root ,返回其最大深度。

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

class Solution {
    public int maxDepth(TreeNode root) {
      if (root == null)   return 0;
   //先创建一个队列
    Queue<TreeNode> que = new LinkedList<>();
    //利用层次遍历
    //加入节点
    que.offer(root);
    int deep =0;
    while(!que.isEmpty()){
        int len = que.size();
        while(len>0){
         TreeNode node = que.poll();
         if(node.left!=null) que.offer(node.left);
         if(node.right!=null) que.offer(node.right);
         len--;
        }
         deep++;
    }
      return deep;
    }
}

二叉树的最小深度 :力扣题目链接

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

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public int minDepth(TreeNode root) {
    Queue<TreeNode> que = new LinkedList<>();
    if(root == null){
        return 0;
    }
    que.offer(root);
    int deep=0;
    while(!que.isEmpty()){
        int size = que.size();
        deep++;
        for(int i =0;i<size;i++){
            TreeNode node = que.poll();
            if(node.left==null && node.right==null){
                return deep;
            }
            if(node.left!=null){
                que.offer(node.left);
            }
            if(node.right!=null){
                que.offer(node.right);
            }
        }
    }
    return deep;
    }
}

利用层序遍历快速刷完了这几道题,发现基本都是一个模板,只是根据每一个题的要求作出一些改变,大体上还是一模一样的。

体会:在外层while中执行的就是当前位置要做的事情,而内层的for循环/while循环,就为下一层做好准备,而size则是控制每层中的节点。

翻转二叉树:力扣题目链接

翻转一棵二叉树。

力扣示例:

这道题用递归来写:

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
    //利用递归
    //递归出口:
    if(root == null){
        return null;
    }
    invertTree(root.left);
    invertTree(root.right);
    swap(root);
    return root;
    }

    //交换的方法
    public void swap(TreeNode root){
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
    }
}

代码很简单,但是要深刻理解递归!

1.递归的出口

2.方法的返回值

当 root 为 null 时,递归的出口就是返回 null。这是因为在二叉树的递归操作中,每个递归步骤都涉及到对左右子树的处理,而 null 表示一个空节点或者叶子节点的空子树。

在这个具体的情境中,当 invertTree 方法递归到叶子节点的左右子树时,这些子树是空的,因此将它们反转后仍然为空。返回 null 可以告诉上一级递归调用,这个空节点的左右子树已经反转完成。

return root, 是为了在递归结束后返回整个树反转后的根节点。

再来练习一道:


 对称二叉树:力扣题目链接

给定一个二叉树,检查它是否是镜像对称的。 

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
    if(root == null){
        return true;
    }
    return dfs(root.left,root.right);
    }

    boolean dfs(TreeNode left , TreeNode right){
        //递归结束条件:
        //左右子树都为空
        if(left == null && right ==null){
            return true;
        }
        //左右节点有一个为空
        if(left == null || right == null){
            return false;
        }
         //左右节点的值不相等
        if(left.val != right.val){
            return false;
        }
        return dfs(left.left,right.right) && dfs(left.right,right.left);
    }
}

这些都是比较简单的递归,思想主要是抓住:

方法的返回值

递归的终止条件

确定递归的单层逻辑

在代码随想录中有对这三部曲的详细概括!即时Review~~~~

我自光芒万丈,

何须他人半点光!

Fighting!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1313364.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

computed 和 watch 的奇妙世界:让数据驱动你的 Vue 应用(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

docker部署go gin框架 Windows环境

目录 文章目的是什么 环境介绍 Windows 环境下 docker 部署 go gin 详细步骤 运行容器时因为挂载文件可能会出现的问题 直接部署gin&#xff08;跳过运行容器时因为挂载文件可能会出现的问题&#xff09; 文章目的是什么 假设我们学习了 go 语言&#xff0c;在 Windows(本…

精选硬件连通性测试工具:企业如何做出明智选择

在当今数字化的商业环境中&#xff0c;企业的硬件连通性至关重要。选择适用的硬件连通性测试工具是确保网络和设备协同工作的关键一步。本文将探讨企业在选择硬件连通性测试工具时应考虑的关键因素&#xff0c;以帮助其做出明智的决策。 1. 功能全面性&#xff1a;首要考虑因素…

PHP微信朋友圈广告植入源码 +提供高效的广告植入解决方案,助力微信朋友圈广告推广

源码介绍 可以无限制帮用户开户&#xff0c;也可以理解为多用户版。 可以管理用户发布文章条数&#xff0c;也可以无限制发布。 用户可以上传多个广告&#xff0c;每个广告分别进行统计展示及点击。 用户一键植入&#xff0c;不用粘贴网址&#xff0c;每篇文章会 分别统计展示…

Peter算法小课堂—简单建模(3)

国王的奖赏系列 国王的奖赏1 题目描述&#xff1a; 你作为战斗英雄得到国王的奖赏&#xff0c;可以在地图上选一块土地。地图里共n*m格土地&#xff0c;第x行第y列的土地格子里标记着d[x][y]的整数价值&#xff0c;可能出现负数。国王让你选择若干列土地&#xff0c;只要是连…

车载以太网笔记

文章目录 以太网协议分层协议中间设备子网掩码物理层测试内容比较杂,后续会整理。 以太网协议分层 协议 中间设备

mfc配置halcon环境

新建mfc窗体 选择基于对话框 打开项目属性 1、附加包含目录添加&#xff1a; $(HALCONROOT)\include;$(HALCONROOT)\include\halconcpp 2、链接器->常规->附加库目录 $(HALCONROOT)\lib\x64-win64 3、链接器->输入->附加依赖项 halcon.lib;halconcpp.lib 在对话…

【期末复习向】n元gram的应用

当 n 1 时&#xff0c; 即出现 在 第 i 位 上 的基 元 w i 独 立于 历 史 。 一元文法也 被 写 为 uni-gram 或 monogram&#xff1b; 当 n 2 时 , 2-gram ( bi-gram ) 被称 为 1 阶 马 尔 可夫 链&#xff1b; 当 n 3 时 , 3-gram( tri-gram ) 被称为 2 阶马尔 可 夫 链 &am…

1-Maven基础

文章目录 Maven基础Maven相关概念构建依赖 Maven用途Maven的工作机制 Maven使用-1-Maven软件的解压与配置步骤1&#xff1a;下载步骤2&#xff1a;解压Maven核心程序步骤3&#xff1a;指定本地仓库步骤4&#xff1a;配置阿里云提供的镜像仓库步骤5&#xff1a;配置 Maven工程的…

2.electron之纯原生js/jquery的桌面应用程序(应用篇)

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中&#xff0c;因此它允许你仅需一个代码仓库&#xff0c;就可以撰写支持 Windows、…

破局:国内市场确实存在“消费升级”和“消费降级”,3.0全新新零售商业模式

国内市场确实存在“消费升级”和“消费降级”两个趋势&#xff0c;这是由于不同消费者群体的需求和购买力存在差异。消费升级主要发生在高端市场&#xff0c;消费者愿意为高品质、高价值、高价格的商品和服务付出更多。而消费降级则主要发生在中低端市场&#xff0c;消费者更加…

抖捧自动直播是什么,系统功能讲解

目前有在做实体行业级商家服务的老板 你还在为不会直播&#xff0c;不敢直播而苦恼吗&#xff1f; 你还在为想做直播&#xff0c;但没空开直播而焦灼吗&#xff1f; 今天&#xff0c;你的问题都可以统统解决 实体行业直播必备黑科技&#xff1a;抖捧AI自动直播 只需要一部手…

uniapp点击按钮,防止按钮多次点击多次触发事件【防抖操作】

图片、 一、在根目录下新建common文件并创建common.js文件&#xff0c;输入下面代码 // 防止处理多次点击function noMultipleClicks(methods, info) {// methods是需要点击后需要执行的函数&#xff0c; info是点击需要传的参数let that this;if (that.noClick) {// 第一次点…

QT笔记(节选)具体图片等下载资源

QT笔记&#xff08;节选&#xff09;具体图片等下载资源 根据b站视频做的笔记&#xff1a; https://www.bilibili.com/video/BV1g4411H78N?p44&spm_id_frompageDriver&vd_sourcea3e6a48ccd3d7d1f969f662653ed68c9 qt是一个跨平台的c图形用户界面应用程序框架&#x…

音乐制作软件Ableton Live 11 mac功能特点

Ableton Live 11 mac是一款数字音频工作站软件&#xff0c;用于音乐制作、录音、混音和现场演出是一款流行的音乐制作软件。 Ableton Live 11 mac特点和功能 Comping功能&#xff1a;Live 11增加了Comping功能&#xff0c;允许用户在不同的录音轨道上进行多次录音&#xff0c;…

1.3 市面常见测试接口的工具

通过前面的学习,涉及接口测试的一些基础知识我们都已经有了了解,那本小节,我们来看看工作中比较常用的测试接口的工具有哪些。 PostmanPostman是我们平常工作中,最最常用的用来测试接口的工具。对于前端开发和后端开发来说,Postman也是工作中必会的工具,那对于我们测试来…

ChatGPT 也宕机了?如何预防 DDOS 攻击的发生

最近&#xff0c;开发人工智能聊天机器人的公司 OpenAI 遭受了一次规模较大的分布式拒绝服务&#xff08;DDoS&#xff09;攻击&#xff0c;导致其旗下的 ChatGPT 服务在短短 12 小时内遭遇了 4 次断网&#xff0c;众多用户遭受了连接失败的问题。 这次攻击事件引起了广泛的关…

图片懒加载vue3-lazy

目录 一、实现原理 二、如何使用 1.安装命令 2.main.js入口文件注册插件 3.template中使用指令 三、总结 最近在重构 博客 的时候遇到页面加载慢的问题&#xff0c;原因是页面小图标太多&#xff0c;一次性加载页面压力超大&#xff0c;打算图片可视区域化懒加载&#xf…

JMeter逻辑控制器

JMeter逻辑控制器 一、IF控制器1、作用2、步骤 二、循环控制器1、作用2、步骤3、线程组和循环控制器的区别&#xff1f; 三、ForEach控制器1、作用2、步骤 一、IF控制器 1、作用 **控制下面的测试元素是否执行**2、步骤 添加线程组用户定义的变量添加if控制器&#xff0c;判断…

力扣90. 子集 II(Java 回溯法)

Problem: 90. 子集 II 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 在本题中所给数组nums中的元素有重复&#xff0c;若再直接使用回溯的话会使得最终的子集有重复&#xff1b;其次我们应该知道求子集&#xff0c;求组合这类使用回溯处理的题目&#xff0c;在核心…