【小嘟陪你刷题14】二叉树的最小深度、二叉树的所有路径、翻转二叉树

news2024/12/27 13:32:42

目录

  • 一、二叉树的最小深度
    • 思路一:深度优先搜索
    • 代码实现
    • 思路二:广度优先搜索
    • 代码实现
  • 二、二叉树的所有路径
    • 思路一:递归法
    • 代码实现
    • 思路二:迭代法
  • 三、翻转二叉树
    • 思路一:递归法
    • 代码实现
    • 思路二:迭代法
    • 代码实现

一、二叉树的最小深度

在这里插入图片描述

思路一:深度优先搜索

我们这里使用后序遍历的方式!
对于每一个非叶子节点,我们只需要分别计算其左右子树的最小叶子节点的深度,就将大问题转化成小问题。
确定终止条件
终止条件也是遇到空节点返回0,表示当前节点的高度为0.

if (root == null) return 0;

确定单层递归的逻辑
这块和求最大深度不一样,会写出如下代码:

int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
int result = 1 + Math.min(leftDepth, rightDepth);
return result;

这个代码就犯了此图中的误区:

在这里插入图片描述
如果这样求,没有左孩子的分支会算为最短深度。
所以,如果左子树为空,右子树不为空,说明最小速度为1 + 右子树的深度。
反之,异然。
最后如果左子树右子树都不为空,返回最小值+1;

代码实现

/**
 * 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) {
        if (root == null) return 0;

        if (root.left == null && root.right == null) {
            return 1;
        }

        int result = 0;
        int leftDepth = minDepth(root.left);
        int rightDepth = minDepth(root.right);
        
        if (root.left == null || root.right == null) return leftDepth + rightDepth + 1;

        result = Math.min(leftDepth, rightDepth) + 1;
        return result;
    }
}

在这里插入图片描述

思路二:广度优先搜索

本题还可以使用层序遍历的方法来解决,思路是一样的。
需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点。

代码实现

/**
 * 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) {
        if (root == null) {
            return 0;
        }
        Deque<TreeNode> deque = new LinkedList<>();
        deque.offer(root);
        int depth = 0;
        while (!deque.isEmpty()) {
            int size = deque.size();
            depth++;
            for (int i = 0; i < size; i++) {
                TreeNode poll = deque.poll();
                if (poll.left == null && poll.right == null) {
                    return depth;
                }
                if (poll.left != null) {
                    deque.offer(poll.left);
                }
                if (poll.right != null) {
                    deque.offer(poll.right);
                }
            }
        }
        return depth;
    }
}

在这里插入图片描述

二、二叉树的所有路径

在这里插入图片描述

思路一:递归法

我们使用前序遍历的方法!
在这里插入图片描述
确定递归终止条件
在写递归的时候我们习惯了这么写:

if (root == null) {
    终止处理逻辑
}

但是本题的终止条件这样写会很麻烦,因为本题要找到叶子节点,就开始结束的处理逻辑了(把路径放进result里)。

那么什么时候算是找到了叶子节点? 是当 cur不为空,其左右孩子都为空的时候,就找到叶子节点。

if (root.left == null && root.right == null) {
}

为什么没有判断cur是否为空呢?因为下面的逻辑可以控制空节点不入循环。

我们使用List结构path来记录路径,所以要把List结构的path转为String格式,再把这个String放进result里。

为什么要是有List?因为在下面处理单层递归逻辑的时候,要做回溯,使用List方便回溯。

确定单层递归逻辑
因为是前序遍历,需要先处理中间节点,中间节点就是我们要记录路劲上的节点,先放进path中。
然后是递归和回溯的过程。上面说过没有判断root是否为空,那么在这里递归的时候,如果为空就不进行下一层递归了。所以递归前要加上判断语句,下面要递归的节点是否为空。
递归完,要做回溯啊,因为path 不能一直加入节点,它还要删节点,然后才能加入新的节点。
回溯和递归是一一对应的,有一个递归,就要有一个回溯,这么写的话相当于把递归和回溯拆开了, 一个在花括号里,一个在花括号外。

所以回溯要和递归永远在一起,世界上最遥远的距离是你在花括号里,而我在花括号外!

代码实现

/**
 * 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<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        List<Integer> paths = new ArrayList<>();
        traversal(root, paths, res);
        return res;
    }

    private void traversal(TreeNode root, List<Integer> paths, List<String> res) {
        paths.add(root.val);
        // 叶子结点
        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) {
            traversal(root.left, paths, res);
            paths.remove(paths.size() - 1);// 回溯
        }
        if (root.right != null) {
            traversal(root.right, paths, res);
            paths.remove(paths.size() - 1);// 回溯
        }
    }
}

在这里插入图片描述

思路二:迭代法

至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,这里除了模拟递归需要一个栈,同时还需要一个栈来存放对应的遍历路径。

/**
 * 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<String> binaryTreePaths(TreeNode root) {
        List<String> result = new ArrayList<>();
        if (root == null)
            return result;
        Stack<Object> stack = new Stack<>();
        // 节点和路径同时入栈
        stack.push(root);
        stack.push(root.val + "");
        while (!stack.isEmpty()) {
            // 节点和路径同时出栈
            String path = (String) stack.pop();
            TreeNode node = (TreeNode) stack.pop();
            // 若找到叶子节点
            if (node.left == null && node.right == null) {
                result.add(path);
            }
            //右子节点不为空
            if (node.right != null) {
                stack.push(node.right);
                stack.push(path + "->" + node.right.val);
            }
            //左子节点不为空
            if (node.left != null) {
                stack.push(node.left);
                stack.push(path + "->" + node.left.val);
            }
        }
        return result;
    }
}

在这里插入图片描述

三、翻转二叉树

在这里插入图片描述

思路一:递归法

在这里插入图片描述
确定终止条件
当前节点为空的时候,就返回

if (root == null) return root;

确定单层递归的逻辑
因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。

swap(root.left, root.right);
invertTree(root.left);
invertTree(root.right);

代码实现

/**
 * 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);
        swapChildren(root);
        return root;
    }

    private void swapChildren(TreeNode root) {
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
    }
}

在这里插入图片描述

思路二:迭代法

代码实现

/**
 * 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;}
        ArrayDeque<TreeNode> deque = new ArrayDeque<>();
        deque.offer(root);
        while (!deque.isEmpty()) {
            int size = deque.size();
            while (size-- > 0) {
                TreeNode node = deque.poll();
                swap(node);
                if (node.left != null) {deque.offer(node.left);}
                if (node.right != null) {deque.offer(node.right);}
            }
        }
        return root;
    }

    public void swap(TreeNode root) {
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
    }
}

在这里插入图片描述

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

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

相关文章

controller传输from-data数据格式的内容,取出传入数据为from-data格式的值

传输from-data数据格式的内容 postman里面的格式如下 接下来&#xff0c;便将上面的内容转换为代码 第一步&#xff1a;将File转为MultipartFile格式 首先&#xff0c;我们只能将File转为改格式才能进行网络传输&#xff0c;转换方式请看这篇博客&#xff1a;https://blog.…

推动行业数字化转型,亚马逊云科技自身就是“好把式”

&#xff08;亚马逊全球副总裁、亚马逊云科技大中华区执行董事张文翊&#xff09; 在2022年10月的亚马逊云科技中国峰会上&#xff0c;亚马逊云科技宣布了四大战略举措——“连中外、襄百业、携伙伴、促绿色“&#xff0c;进一步为中国本地客户赋能数字化探索与创新&#xff0…

顺序表实现—数据结构

文章目录一、顺序表概念及结构二、动态顺序表和静态顺序表的选择三、动态顺序表的实现逻辑&#xff08;1&#xff09;创建结构体&#xff08;2&#xff09;具体函数实现&#xff08;*&#xff09;顺序表初始化&#xff08;*&#xff09;释放顺序表&#xff08;*&#xff09;打印…

青少年python系列 21.turtle库绘制一个8

#绘制一个8import turtle#上方的小圆&#xff0c;圆心在左turtle.circle(80)#下方的大圆&#xff0c;圆心在右turtle.circle(-100)turtle.done() 青少年python教学视频ppt源码 青少年python系列目录_老程序员115的博客-CSDN博客 csdn文章推荐受影响解决办法10个字10行 csdn文…

梦开始的地方—— C语言指针入门

文章目录指针入门1.指针概念2. 指针和指针类型3. 野指针造成野指针的原因如何避免野指针4. 指针的运算指针加减整数指针的运算关系指针的关系运算5.指针和数组6. 二级指针7. 指针数组指针入门 1.指针概念 指针(Pointer) 是编程语言中的一个对象&#xff0c;利用地址&#xff…

31、Java——JDBC实现账号密码登录

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;乐趣国学的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

Kong自动注册kong-spring-boot-stater

前言 kong-spring-boot-stater框架是为了解决SpringBoot项目和kong网关的自动注册&#xff0c;虽然Kong网关有提供可视化管理后台的操作界面&#xff0c;但是在多服务、多环境的时候在管理后台挨个配置每个服务节点是比较麻烦的&#xff0c;所以这也是kong-spring-boot-stater…

P3654 First Step (ファーストステップ)——暴力枚举

First Step (ファーストステップ) 题目背景 知らないことばかりなにもかもが&#xff08;どうしたらいいの&#xff1f;&#xff09; 一切的一切 尽是充满了未知数&#xff08;该如何是好&#xff09; それでも期待で足が軽いよ&#xff08;ジャンプだ&#xff01;&#xff09…

项目流程管理工具:OmniPlan Pro 4 中文

如何更好的管理项目流程&#xff1f;OmniPlan Pro 4中文是个很好的帮手&#xff0c;非常好用的项目流程管理工具&#xff0c; 强大的规划&#xff0c;管理复杂性&#xff1a; 引入三个新的内置模板&#xff1a;标准项目、标准项目&#xff08;样式&#xff09;和简单项目。 …

【TA】Unity角色二次元风格渲染

NRMToonLitSample Author : 文若 我的Demo地址 &#xff1a; NRMToonLitSample 学习视频地址 &#xff1a; Kerry大佬的 技术美术实战培训课程——卡通人物渲染方案 文章目录NRMToonLitSample1. 模型贴图基本信息2. 基础渲染效果2.1 基础shader Toon2.2 光照模型效果第一步&…

【从零到一的Raspberry】树莓派踩坑实录(一)系统安装与简单开发

写在前面 本系列作为树莓派上手记录&#xff0c;同时将本人的踩坑以及参考进行记录汇总&#xff0c;必要时罗列出小组分工&#xff0c;作为《嵌入式软开》小组参考文件。 0 硬件准备 名称描述树莓派3B支持wifi&#xff0c;包含了散热器、外壳、电源线等配件网线感谢王emo同学…

【小程序websocket前后端交互】uniapp写微信小程序聊天功能功能,websocket交互功能,心跳重连【详细注释,复制即用】

前言 这几天在做的一个需求&#xff0c;就是要写一个小程序端的页面&#xff0c;用于跟客服聊天。 然后就用到了websocket技术&#xff0c;以前我做过网页版的&#xff0c;但是做小程序后发现网页版的逻辑放过来没问题&#xff0c;但是很多的方法和api是不生效的&#xff0c;所…

立方体的表面积 长方体的表面积 公里转换为米 温度对照

立方体的表面积 难度&#xff1a;青铜 时间限制&#xff1a;1秒 占用内存&#xff1a;64 M 输入立方体边长&#xff0c;输出立方体的表面积。不考虑非法输入。格式 输入格式&#xff1a;输入实型 输出格式&#xff1a;输出实型 #include<bits/stdc.h> using namespace s…

万字长文的CSS与JavaScript简易学习

近期学习web笔记&#xff0c;可供参考 目录 css: css导入方式&#xff1a; css选择器&#xff1a; javascript: javascript介绍&#xff1a; js引入方式&#xff1a; js书写语法&#xff1a; js变量&#xff1a; 5种原始类型&#xff1a; 运算符&#xff1a; JavaScr…

推荐一款基于.Net Core开发简约漂亮的 WPF UI库

今天给大家推荐一个开源WPF UI库。 项目简介 这是一款使用简单、UI评论的WPF UI库&#xff0c;借鉴了多个开源框架。UI简单清晰、大气。 技术架构 1、跨平台&#xff1a;这是基于.Net Core开发的系统&#xff0c;可以部署在Docker, Windows, Linux, Mac。 2、开发环境&…

微视网媒:沃尔沃质量有什么魅力 让大佬罗永浩、樊登纷纷翻牌S90?

在消费市场&#xff0c;选对代言人&#xff0c;产品就成功了一半&#xff0c;这话可是一点都没说错。 从一定程度上来说&#xff0c;代言人就是产品对外形象的展示&#xff0c;甚至有不少消费者还会因为代言人激情下单。 当然&#xff0c;成也代言&#xff0c;败也代言&#xf…

拉格朗日对偶问题的一些介绍

文章目录参考前言拉格朗日函数例1例2拉格朗日函数的对偶问题参考 “拉格朗日对偶问题”如何直观理解&#xff1f;“KKT条件” “Slater条件” “凸优化”打包理解 感觉有时间看视频的还是看视频比较好&#xff0c;本文只是记录一下以防以后忘记。 前言 还记得SVM里用到拉格朗…

Python代码的编写运行方式简介

Python代码的编写运行方式简介 Python编写方式 Python 是一种解释型的脚本编程语言&#xff0c;支持两种代码编写方式&#xff1a;交互命令行方式和运行.py代码文件方式。 Python的交互命令行方式和直接运行.py代码文件方式有什么区别呢&#xff1f; 交互模式&#xff0c;相当…

Python爬虫|采集开源众包的悬赏任务,自动翻页

前言 现在互联网,有很多网站提供一些接单外派的形式,提供给有能力的人或者团队去接单。比如说,很多人熟悉的猪八戒,程序员客栈,CODING 码市,开源众包等等平台,相信很多同学也都知道。 如果要第一时间了解某个接单平台发布的第一手悬赏任务,选择爬虫也是非常不错的选择…

websocket接口自动化集成pytest测试框架

01、websocket协议 1、介绍 WebSocket是一种在单个TCP通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455&#xff0c;并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向…