Day23|二叉树part09:669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树、总结篇

本文主要是介绍Day23|二叉树part09:669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树、总结篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

669. 修剪二叉搜索树

一刷完全没有思路,现在有点思路了,但是还是独立写不出来。

class Solution {public TreeNode delete(TreeNode node, int low, int high){if(node == null){return null;}if(node.val < low){return delete(node.right, low, high);}else if(node.val > high){return delete(node.left, low, high);}node.left = delete(node.left, low, high);node.right = delete(node.right, low, high);return node;}public TreeNode trimBST(TreeNode root, int low, int high) {return delete(root, low, high);}
}
  • 如果node(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。

所以,如果当前节点的值小于low,那么它的左子树中的所有节点的值也一定小于low。因此,我们可以放心地舍弃当前节点及其左子树,然后在右子树中递归寻找满足条件的节点。

我们会删除那些值不在给定范围内的节点,但是这个“删除”实际上是在寻找和构建新的二叉搜索树,而不是真正意义上的删除操作

108.将有序数组转换为二叉搜索树

class Solution {public void testSortedArrayToBST() {// 创建一个二叉搜索树int[] nums = new int[]{-10,-3,0,5,9};TreeNode root = sortedArrayToBST(nums);System.out.println(root.val);}public TreeNode buildBST(int[] nums, int i, int j){if(i > j){return null;}int middle = (i + j) / 2;TreeNode node = new TreeNode(nums[middle]);node.left = buildBST(nums, i, middle - 1);node.right = buildBST(nums, middle + 1, j);return node;}public TreeNode sortedArrayToBST(int[] nums) {return buildBST(nums, 0, nums.length - 1);}
}
  • 这里记得传入的是0, nums.length - 1,不然会越界;

538.把二叉搜索树转换为累加树

看着很难,没想到这么简单!记住遍历顺序是中序但是右中左,用一个sum维护总和。

class Solution {private int sum = 0;public void traversal(TreeNode node){if(node == null){return;}traversal(node.right);sum += node.val;node.val = sum;traversal(node.left);return;}public TreeNode convertBST(TreeNode root) {traversal(root);return root;}
}
  • 为什么是右根左,因为二叉树左小右大。

如果我们按照右-根-左的顺序遍历并更新节点值,那么当我们访问一个节点时,我们已经访问过所有大于该节点值的节点,并且已经计算了它们的和。因此,我们可以直接使用这个和来更新当前节点的值。

114. 二叉树转化为链表

  • 注意 flatten 函数的签名,返回类型为 void,也就是说题目希望我们在原地把二叉树拉平成链表。
  • 否则可以采用这样的方法:
class Solution {private TreeNode dummy = new TreeNode(-1);private TreeNode p = dummy;public void traversal(TreeNode node){if(node == null){return;}p.right = new TreeNode(node.val);p = p.right;traversal(node.left);traversal(node.right);}public void flatten(TreeNode root) {traversal(root);root = dummy.right;}
}

(但是运行后发现并没有修改root的值,这是因为:

,flatten 方法试图修改 root 的引用,但是在 Java 中,参数传递是按值传递的,这意味着你只是复制了 root 的引用,而不是引用本身。因此,当你修改 root 时,你只是修改了这个复制的引用,而不是原始的 root 引用。

  • 因为只能在树上修改,方法是先把左右子树拉平,再把右子树的平序列接到左子树的平序列下面:
class Solution {public void traversal(TreeNode node){if(node == null){return;}//拉平traversal(node.left);traversal(node.right);//保存当前节点的左子节点和右子节点的引用。TreeNode left = node.left;TreeNode right = node.right;node.left = null;node.right = left;//接上TreeNode p = node;while (p.right != null) {p = p.right;}p.right = right;}public void flatten(TreeNode root) {traversal(root);}
}

二叉树总结篇

求二叉树的属性

  • 二叉树:是否对称(opens new window)
    • 递归:后序,比较的是根节点的左子树与右子树是不是相互翻转
    • 迭代:使用队列/栈将两个节点顺序放入容器中进行比较
  • 二叉树:求最大深度(opens new window)
    • 递归:后序,求根节点最大高度就是最大深度,通过递归函数的返回值做计算树的高度
    • 迭代:层序遍历
  • 二叉树:求最小深度(opens new window)
    • 递归:后序,求根节点最小高度就是最小深度,注意最小深度的定义
    • 迭代:层序遍历
  • 二叉树:求有多少个节点(opens new window)
    • 递归:后序,通过递归函数的返回值计算节点数量
    • 迭代:层序遍历
  • 二叉树:是否平衡(opens new window)
    • 递归:后序,注意后序求高度和前序求深度,递归过程判断高度差
    • 迭代:效率很低,不推荐
  • 二叉树:找所有路径(opens new window)
    • 递归:前序,方便让父节点指向子节点,涉及回溯处理根节点到叶子的所有路径
    • 迭代:一个栈模拟递归,一个栈来存放对应的遍历路径
  • 二叉树:递归中如何隐藏着回溯(opens new window)
    • 详解二叉树:找所有路径 (opens new window)中递归如何隐藏着回溯
  • 二叉树:求左叶子之和(opens new window)
    • 递归:后序,必须三层约束条件,才能判断是否是左叶子。
    • 迭代:直接模拟后序遍历
  • 二叉树:求左下角的值(opens new window)
    • 递归:顺序无所谓,优先左孩子搜索,同时找深度最大的叶子节点。
    • 迭代:层序遍历找最后一行最左边
  • 二叉树:求路径总和(opens new window)
    • 递归:顺序无所谓,递归函数返回值为bool类型是为了搜索一条边,没有返回值是搜索整棵树。
    • 迭代:栈里元素不仅要记录节点指针,还要记录从头结点到该节点的路径数值总和

#二叉树的修改与构造

  • 翻转二叉树(opens new window)
    • 递归:前序,交换左右孩子
    • 迭代:直接模拟前序遍历
  • 构造二叉树(opens new window)
    • 递归:前序,重点在于找分割点,分左右区间构造
    • 迭代:比较复杂,意义不大
  • 构造最大的二叉树(opens new window)
    • 递归:前序,分割点为数组最大值,分左右区间构造
    • 迭代:比较复杂,意义不大
  • 合并两个二叉树(opens new window)
    • 递归:前序,同时操作两个树的节点,注意合并的规则
    • 迭代:使用队列,类似层序遍历

#求二叉搜索树的属性

  • 二叉搜索树中的搜索(opens new window)
    • 递归:二叉搜索树的递归是有方向的
    • 迭代:因为有方向,所以迭代法很简单
  • 是不是二叉搜索树(opens new window)
    • 递归:中序,相当于变成了判断一个序列是不是递增的
    • 迭代:模拟中序,逻辑相同
  • 求二叉搜索树的最小绝对差(opens new window)
    • 递归:中序,双指针操作
    • 迭代:模拟中序,逻辑相同
  • 求二叉搜索树的众数(opens new window)
    • 递归:中序,清空结果集的技巧,遍历一遍便可求众数集合
    • 二叉搜索树转成累加树(opens new window)
    • 递归:中序,双指针操作累加
    • 迭代:模拟中序,逻辑相同

#二叉树公共祖先问题

  • 二叉树的公共祖先问题(opens new window)
    • 递归:后序,回溯,找到左子树出现目标值,右子树节点目标值的节点。
    • 迭代:不适合模拟回溯
  • 二叉搜索树的公共祖先问题(opens new window)
    • 递归:顺序无所谓,如果节点的数值在目标区间就是最近公共祖先
    • 迭代:按序遍历

#二叉搜索树的修改与构造

  • 二叉搜索树中的插入操作(opens new window)
    • 递归:顺序无所谓,通过递归函数返回值添加节点
    • 迭代:按序遍历,需要记录插入父节点,这样才能做插入操作
  • 二叉搜索树中的删除操作(opens new window)
    • 递归:前序,想清楚删除非叶子节点的情况
    • 迭代:有序遍历,较复杂
  • 修剪二叉搜索树(opens new window)
    • 递归:前序,通过递归函数返回值删除节点
    • 迭代:有序遍历,较复杂
  • 构造二叉搜索树(opens new window)
    • 递归:前序,数组中间节点分割
    • 迭代:较复杂,通过三个队列来模拟

这篇关于Day23|二叉树part09:669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树、总结篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/855997

相关文章

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Java对象转换的实现方式汇总

《Java对象转换的实现方式汇总》:本文主要介绍Java对象转换的多种实现方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java对象转换的多种实现方式1. 手动映射(Manual Mapping)2. Builder模式3. 工具类辅助映

python实现svg图片转换为png和gif

《python实现svg图片转换为png和gif》这篇文章主要为大家详细介绍了python如何实现将svg图片格式转换为png和gif,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录python实现svg图片转换为png和gifpython实现图片格式之间的相互转换延展:基于Py

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

C#实现将Excel表格转换为图片(JPG/ PNG)

《C#实现将Excel表格转换为图片(JPG/PNG)》Excel表格可能会因为不同设备或字体缺失等问题,导致格式错乱或数据显示异常,转换为图片后,能确保数据的排版等保持一致,下面我们看看如何使用C... 目录通过C# 转换Excel工作表到图片通过C# 转换指定单元格区域到图片知识扩展C# 将 Excel

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a