代码随想录--二叉树章节总结 Part III

news2024/12/22 22:41:25

代码随想录–二叉树章节总结Part III

1.Leetcode106 从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

解题思路1: 递归方法。利用后序遍历解决。

  • 首先判断如果数组没没有元素,则返回空
  • 如果数组中有元素,则取后序遍历数组中的最后一个元素,创建根结点。
  • 然后根据根结点的值,找到这个值在中序遍历中的下标。根据下标,将中序遍历分为左右子树。
  • 然后递归的根据分开后的遍历序列,构建左右子树

注意,在后序遍历中,无法根据根结点来判断哪些元素属于左子树,哪些属于右子树。但是左右子树划分的长度和中序遍历是一致的。

image-20230128114451284

public TreeNode buildTree(int[] inorder, int[] postorder) {
  	return f(inorder, postorder);
}
private TreeNode f(int[] inorder, int[] postorder) {
    if(postorder.length == 0) return null;
    // 处理根结点 从后序遍历中取出最后的元素,创建结点
    TreeNode root = new TreeNode(postorder[postorder.length - 1]);
    int index;
    for (index = 0; index < inorder.length; index++) {
      	if (inorder[index] == root.val) break;
    }
    // 左
    root.left = f(Arrays.copyOfRange(inorder, 0, index), Arrays.copyOfRange(postorder, 0, index));
    // 右
    root.right = f(Arrays.copyOfRange(inorder, index + 1, inorder.length), Arrays.copyOfRange(postorder, index, postorder.length - 1));
    // 根
    return root;
}

此外需要注意的是,Arrays.copyOfRange()的区间是左闭右开的

2.Leetcode105 从中序与前序遍历序列构造二叉树

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

解题思路: 和上面的方法一样,采用递归的后序遍历方法。

  • 首先如果两个数组任意一个为空,则直接返回空
  • 然后从先序遍历数组中取出第一个元素,用来创建根结点
  • 然后找到根结点在中序遍历中的位置,将遍历序列进行划分
  • 然后递归的构建根结点的左右子树
  • 最后返回根结点
public TreeNode buildTree(int[] preorder, int[] inorder) {
  	return f(inorder, preorder);
}

private TreeNode f(int[] inorder, int[] preorder) {
    if (preorder.length == 0 || inorder.length == 0) return null;
    // 从前序遍历序列中取出第一个元素作为根结点
    int root_val = preorder[0];
    // 构建根结点
    TreeNode root = new TreeNode(root_val);

    // 查找根结点在中序遍历中的位置
    int index;
    for (index = 0; index < inorder.length; index++) {
      	if (inorder[index] == root_val) break;
    }

    TreeNode left = f(Arrays.copyOfRange(inorder, 0, index), Arrays.copyOfRange(preorder, 1, index + 1));
    TreeNode right = f(Arrays.copyOfRange(inorder, index + 1, inorder.length), Arrays.copyOfRange(preorder, index + 1, preorder.length));

    root.left =left;
    root.right = right;
    return root;
}

前序遍历和中序遍历的划分:

注意这里的区间我用的是左闭右开区间,为了和Arrays.copyOfRange()保持一致

image-20230128120545098

3.Leetcode654 最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。

示例:

654.最大二叉树

解题思路: 利用递归,具体的思路和上面两道题是一样的,只是划分数组的方式不一样而已

  • 首先判断数组长度是为0,如果为0,则直接返回null
  • 否则将获取到数组中的最大值,根据最大值构建根结点
  • 并且根据最大值的下标将数组划分为两部分,利用这两部分分别构建左右子树
  • 最后返回根结点即可。

需要注意的是边界条件的处理

  • 最大值在数组的最后一个元素时,那么构建的右子树应该为空
  • 最大值在数组的第一个元素时,那么构建的左子树为空。

在代码中需要进行判断,确保不会越界的问题

image-20230128132011999

public TreeNode constructMaximumBinaryTree(int[] nums) {
  	return f(nums);
}

/**
 * 构建二叉树
 * @param nums
 * @return
*/
private TreeNode f(int[] nums) {
    // 如果数组中没有元素,则返回空
    if (nums.length == 0) return null;
    // 获取数组中最大元素下标
    int index = maxNums(nums);
    // 创建根结点
    TreeNode root = new TreeNode(nums[index]);
    // 递归创建左右子树
    TreeNode left = null;
    TreeNode right = null;
    if (index > 0) {
      	left = f(Arrays.copyOfRange(nums, 0, index));
    }
    if (index + 1 < nums.length) {
      	right = f(Arrays.copyOfRange(nums, index + 1, nums.length));
    }

    // 处理根
    root.left = left;
    root.right = right;
    return root;
}

/**
 * 返回数组中最大值的下标
 * @param nums
 * @return
*/
private int maxNums(int[] nums) {
    if (nums.length == 1) return 0;
    int max = nums[0];
    int index = 0;
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] > max) {
            max = nums[i];
            index = i;
        }
    }
    return index;
}

4.Leetcode617 合并二叉树

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例如下:

img

解题思路: 利用递归求解。使用前序遍历,当遍历到结点为空的时候,则结束递归。否则继续递归合并左右子树。

public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
    if (root1 == null) return root2;
    if (root2 == null) return root1;

    // root1 root2 都不为空
    root1.val += root2.val;

    // 递归处理左右子树
    TreeNode left = mergeTrees(root1.left, root2.left);
    TreeNode right = mergeTrees(root1.right, root2.right);
    root1.left = left;
    root1.right = right;
    return root1;
}

5.Leetcode700 二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点 root 和一个整数值 val。

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

解题思路: 直接利用递归前序遍历即可。

  • 终止条件是结点为空。
  • 根结点处理:如果根结点的值等于val,直接返回根结点。否则根据val的大小去递归搜索左子树或者右子树即可。
public TreeNode searchBST(TreeNode root, int val) {
    // 递归终止条件
    if (root == null) return null;
    // 处理根结点
    if (root.val == val) return root;
    if (root.val > val) return searchBST(root.left, val);
    if (root.val < val) return searchBST(root.right, val);
    return null;
}

解题思路2:迭代法。从根结点开始遍历,直到遍历到空结点为止。在循环中,根据val和root的值判断搜索方向。

public TreeNode searchBST(TreeNode root, int val) {
    if (root == null) return null;
    TreeNode cur = root;
    while (cur != null) {
        if (cur.val == val) return cur;
        if (cur.val > val) 
            cur = cur.left;
        else if (cur.val < val)
            cur = cur.right;
    }
    return null;
}

6.Leetcode98 验证平衡二叉树

给你一个二叉树的根节点root,判断其是否是一个有效的二叉搜索树。

有效二叉搜索树定义如下:

  • 节点的左子树只包含小于当前节点的数
  • 节点的右子树只包含大于当前节点的数
  • 所有左子树和右子树自身必须也是二叉搜索树

错误思路: 利用递归进行前序遍历,先判断根结点是不是满足上面的条件。如果满足,则继续判断左右子树是不是满足条件。

public boolean isValidBST(TreeNode root) {
    // 如果为空 则返回true
    if (root == null) return true;
    // 如果是叶子结点,则返回true
    if (root.left == null && root.right == null) return true;

    // 如果根只有左子树
    if (root.left != null && root.right == null) {
        boolean flag = root.val > root.left.val;
        return flag && isValidBST(root.left);
    }
    // 如果只有右子树
    if (root.left == null && root.right != null) {
        boolean flag = root.val < root.right.val;
        return flag && isValidBST(root.right);
    }

    boolean flag = (root.val > root.left.val) && (root.val < root.right.val);
    return flag && isValidBST(root.left) && isValidBST(root.right);
}

上面的代码看似是对的,但是针对下面这种情况

  • 二叉树为[5,4,6,null,null,3,7]
  • 3这个结点在就不满足条件

因为只判断了当前结点和左右孩子。

正确思路是:二叉搜索树的中序遍历是严格单调递增的。应该利用这一条性质进行解题

解题思路1:利用中序遍历和数组。将中序遍历序列保存到数组中,然后判断这个数组中的元素是不是严格单调递增的即可。

public boolean isValidBST(TreeNode root) {
    ArrayList<Integer> list = new ArrayList<>();
    inorder(root, list);
    System.out.print(list);
    // 注意这里i从1开始
    for (int i = 1; i < list.size(); i++) {
        if (list.get(i-1) >= list.get(i))
          	return false;
    }
    return true;
}
private void inorder(TreeNode root, ArrayList<Integer> list) {
    if (root == null) return;
    inorder(root.left, list);
    list.add(root.val);
    inorder(root.right, list);
}

解题思路2: 优化思路1,不采用数据进行保存,而是定一个全局遍历用来记录每一次遍历结点的前一个结点,然后这两个结点的val进行比较即可。

private TreeNode preNode = null;
public boolean isValidBST(TreeNode root) {
    if (root == null) return true;
    // 遍历左边
    boolean left = isValidBST(root.left);
    if (left == false) return false;

    // preNode != null 主要是在根结点进入递归的时候preNode还是空 if应该不成立 否则就直接返回false了
    if (preNode != null && preNode.val >= root.val)
        return false;
    preNode = root;
    // 实际上应该是左&&中&&右 但是执行到这一步 左中一定为true 所以省略
    return isValidBST(root.right);
}

7.Leetcode530 二叉搜索树的最小绝对差

给你一个二叉搜索树的根节点root,返回树中任意两不同节点值之间的最小差值 。差值是一个正数,其数值等于两值之差的绝对值。

问题分析:二叉搜索树的中序遍历是单调递增的,那么就说明了最小绝对差只能存与中序遍历两两相邻的两个元素之间,因此只需要获取到中序遍历,然后在两两比较即可。

解题思路1: 递归求中序遍历,将遍历序列保存到数组中。然后两个指针遍历数组,每次计算两个指针指向的元素的val差的绝对值,最终找到最小值返回。

public int getMinimumDifference(TreeNode root) {
    ArrayList<Integer> list = new ArrayList<>();
    inorder(root, list);
    int min = Integer.MAX_VALUE;
    for (int i = 1; i < list.size(); i++) {
        int diff = Math.abs(list.get(i-1) - list.get(i));
        if (diff < min)
          	min = diff;
    }
    return min;
}
private void inorder(TreeNode root, ArrayList<Integer> list) {
    if (root == null) return;
    inorder(root.left, list);
    list.add(root.val);
    inorder(root.right, list);
}

解题思路2: 和上面的题一样,可以使用指针记录上一个元素的地址,从而不使用数组即可。

private int min = Integer.MAX_VALUE;
private TreeNode pre = null;
// 定义全局变量
public int getMinimumDifference(TreeNode root) {
    if (root == null) return 0;
    inorder(root);
    return min;
}
private void inorder(TreeNode root) {
    if (root == null) return;
    inorder(root.left);
    if (pre != null) {
        int diff = Math.abs(pre.val - root.val);
        min = Math.min(diff, min);
    }
    pre = root;
    inorder(root.right);
}

这里我们发现,二叉树的递归函数有一些是有返回值的,有一些又是没有返回值的。

  • 通常情况下,如果需要遍历所有结点,一般是没有返回值的,如这个题就需要遍历所有结点
  • 对于遍历部分结点就可以得到结果的题,大部分递归函数是有返回值的
  • 此外,如果要求返回满足条件的结点或者子树,那么也是需要有返回值的

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

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

相关文章

【Go基础】并发编程

文章目录1. 并发模型2. Goroutine的使用3. Channel的同步与异步4. 并发安全性5. 多路复用6. 协程泄漏7. 协程管理1. 并发模型 任何语言的并行&#xff0c;到操作系统层面&#xff0c;都是内核线程的并行。同一个进程内的多个线程共享系统资源&#xff0c;进程的创建、销毁、切…

【监控开发】jps命令怎么远程调用另一个IP的机器,jstatd服务支持

jsp命令远程调用咩有Linux服务器启动jstatd服务的时候Linux服务器如何启动jstatd服务1.查找jdk所在目录2.在jdk的bin目录下创建文件jstatd.all.policy3.给这个文件赋权4.这个文件写入安全配置&#xff0c;赋值粘贴即可5.启动jstatd服务6.查看是否启动成功再去另外一台服务器调用…

第一章:Go语言为并发而生

在早期 CPU 都是以单核的形式顺序执行机器指令。Go语言的祖先C语言正是这种顺序编程语言的代表。顺序编程语言中的顺序是指&#xff1a;所有的指令都是以串行的方式执行&#xff0c;在相同的时刻有且仅有一个 CPU 在顺序执行程序的指令。 随着处理器技术的发展&#xff0c;单核…

C语言深度解剖-关键字(4)

目录 signed、unsigned 关键字补充内容 关于大端和小端 大小端存储数据方式 判断大小端 深入理解数据存储 练习&#xff1a; 写在最后&#xff1a; signed、unsigned 关键字补充内容 关于大端和小端 我们通过在内存中存储一个值&#xff0c; 用于观察数据在内存中的存…

Python连接Liunx中mysql数据库-保姆级教程

首先确保你的liunx中已经安装好了mysql数据库如果没有安装mysql数据库看这篇文章Centos6从零开始安装mysql和tomcat后台环境&#xff0c;并成功部署Tomcat项目图文详细过程 python连接Liunx中mysql数据库进行增删改查liunx中相关环境改变Python中连接liunx中的mysql数据库在Nav…

上班第一件事:马上卸载这个恶心的软件!

一上班就被Notepad给恶心到了。“如果不同意政治观点&#xff0c;就在你的源码中添加随机字符。”这个Notepad作者侯今吾真是把自己当做大人物了啊&#xff1f;&#xff01;率性而为&#xff0c;根本不再考虑用户的感受了。 这个Twitter帖子很快就被一片骂声淹没&#xff0c;这…

【每日CSS3代码】

1-1 两栏布局【1/27】 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…

OpenJudge NOI 2.4 8463:Stupid cat Doge

【题目链接】 OpenJudge NOI 2.4 8463:Stupid cat & Doge 【题目考点】 1. 递归 2. 分形图 【解题思路】 解法1&#xff1a;递归 1级正方形边长是212^121&#xff0c;2级正方形边长为222^222&#xff0c;。。。&#xff0c;n级正方形边长为2n2^n2n&#xff0c;总格子…

autojs画六边形

牙叔教程 简单易懂 界面基础代码 "nodejs ui"; require("rhino").install(); const ui require("ui"); class MainActivity extends ui.Activity {constructor() {super();}get layoutXmlFile() {return "layout.xml";}onContentVi…

高效学 C++|继承与组合

继承是面向对象程序设计的重要特性之一。作为面向对象的编程语言&#xff0c;C语言也自然支持这个特性。继承是代码复用的基本方法之一&#xff0c;也是接口和复用设计的关键。本文介绍继承的含义和继承与组合的关系。 01、继承的含义 面向对象程序设计通过将问题域中的事物抽…

Web 应用程序的文件系统写入能力

介绍 NodeJS 之前&#xff0c;JS 操作文件只能通过 HTML <input type"file"> 元素或 XMLHttpRequest&#xff08;或之后的 fetch&#xff09;&#xff0c;来对本地文件进行一些浏览和上传操作。NodeJS 给予了 JS 操作系统底层 API 的能力&#xff0c;但这只能…

章节7 查看和处理文件内容

7-查看和处理文件内容 文本文件 ASCII、UTF-8、Unicode、ANSItxt、xml、conf、properties、yml等配置文件、日志文件、源代码 二进制文件 可执行文件、图片、音频、视频 cat 全拼&#xff1a;concatenate [kənˈkt(ə)nˌeɪt] 连接 格式&#xff1a;cat 文件名 more/…

eyeurl—一款网页批量截图工具

eyeurl使用说明 开发说明 eyeurl由作者&#xff1a;云小书 开发&#xff0c;源于日常渗透测试中&#xff0c;信息收集到的url过多&#xff0c;挨个打开查看比较繁琐&#xff0c;且效率极低&#xff0c;网上有大佬开发的eyewitness&#xff0c;且ui布局各方面都比较完善&#…

sadserver 题目思路概述

背景 从 阮一峰老师的博客 了解到 sadserver 可以在线挑战一些 linux 指令相关问题&#xff08;整体难度一般&#xff0c;但做题体验不错&#xff0c;有提示&#xff09;&#xff0c;这里将目前网站提供的的16道题进行简单解答&#xff0c;提供思路和相关指令 本文csdn 博客地…

初识Java虚拟机

1.概述 Java虚拟机&#xff1a;Java Virtual Machine。正是有了Java虚拟机&#xff0c;Java语言实现了跨平台的特性&#xff0c;一次编译&#xff0c;多处运行。 目前使用范围最广的虚拟机就是Hotspot VM&#xff0c;它是OracleJDK和OpenJDK中的默认Java虚拟机。 相比于其他…

[Android Studio]开发APP应用出现软件程序打开闪退的排错

&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea; Android Debug&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea; Topic 发布安卓学习过程中遇到问题解决过程&#xff0c;希望我的解决方案可以对小伙伴们有帮助。 &#x1f4cb;笔记目…

你还没用过Mybatis-Plus?丝般顺滑,快速上手!

一、概述 1.1、什么是MyBatis-Plus MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 1.2、特性 无侵入&#xff1a;只做…

RabbitMQ入门前篇

本篇博文目录:一.RabbitMQ1.消息队列2.RabbitMQ3.安装RabbitMQ4.RabbitMQ常用命令二.使用RabbitMQ进行编程1.AMQP2.第一次MQ通信三.RabbitMQ六中工作模式1.RabbitMQ2.Work queues3.pub/sub订阅发布模式4.Routing模式5.主题Topic模式四.RabbitMQ消息确认机制五.源代码下载一.Rab…

我性格比较内向,适合做管理吗?

许多刚走上管理岗位的朋友&#xff0c;都有这样的困惑&#xff1a;1.我比较内向&#xff0c;不适合做管理。2.我不擅长演讲&#xff0c;没有领导才能。3.我太谨小慎微了&#xff0c;做不好领导。4.我太喜欢出风头&#xff0c;静不下心来做管理。5.我太强势了&#xff0c;团队很…

GuLi商城-项目初始结构创建,GitHub仓库创建

GitHub账号和密码 账号&#xff1a;11360XXXXXqq.com 密码&#xff1a;ZH**SH*19**1016 新建仓库&#xff1a; gulimall 记得勾选下Add a README file&#xff0c;上面忘记勾选了&#xff0c;实际建议还是要勾选下 复制路径&#xff1a; 打开IDEA检出项目 创建商品微服务模…