【无标题】每天一道算法练习题--Day24 第一章 --算法专题 --- ----------平衡二叉树专题

news2024/11/16 1:40:31

力扣关于平衡二叉树的题目还是有一些的,并且都非常经典,推荐大家练习。今天给大家精选了 4 道题,如果你彻底搞明白了这几道题,碰到其他的平衡二叉树的题目应该不至于没有思路。当你领会了我的思路之后, 建议再找几个题目练手,巩固一下学习成果。

110. 平衡二叉树(简单)

最简单的莫过于判断一个树是否为平衡二叉树了,我们来看下。

题目描述

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

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

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

示例 1:

给定二叉树 [3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7
返回 true 。

示例 2:

给定二叉树 [1,2,2,3,3,null,null,4,4]

       1
      / \
     2   2
    / \
   3   3
  / \
 4   4
返回 false


思路

由于平衡二叉树定义为就是一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1。

用伪代码描述就是:

if abs(高度(root.left) - 高度(root.right)) <= 1
   and root.left 也是平衡二叉树 
   and root.right 也是平衡二叉树:
   
    print('是平衡二叉树')
    
else:
    print('不是平衡二叉树')

而 root.left 和 root.right 如何判断是否是二叉平衡树就和 root 是一样的了,可以看出这个问题有明显的递归性。

因此我们首先需要知道如何计算一个子树的高度。这个可以通过递归的方式轻松地计算出来。计算子树高度的 Python

代码如下:

def dfs(node):
    if not node: return 0
    
    l = dfs(node.left)
    r = dfs(node.right)
    
    return max(l, r) + 1

代码

代码支持: Python3

Python3 Code:

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        def dfs(node):
            if not node: return 0
            l = dfs(node.left)
            r = dfs(node.right)
            return max(l, r)  + 1
            
        if not root: return True
        if abs(dfs(root.left) -  dfs(root.right)) > 1: return False
        return self.isBalanced(root.left) and self.isBalanced(root.right)

复杂度分析

  • 时间复杂度:对于 isBalanced 来说,由于每个节点最多被访问一次,这部分的时间复杂度为 O ( N ) O(N) O(N),而 dfs 函数 每次被调用的次数不超过 l o g N log N logN,因此总的时间复杂度为 O ( N l o g N ) O(NlogN) O(NlogN),其中 N N N 为 树的节点总数。
  • 空间复杂度:由于使用了递归,这里的空间复杂度的瓶颈在栈空间,因此空间复杂度为 O ( h ) O(h) O(h),其中 h h h 为树的高度。

108. 将有序数组转换为二叉搜索树(简单)

108 和 109 基本是一样的,只不过数据结构不一样,109 变成了链表了而已。由于链表操作比数组需要考虑更多的因素,因此 109 是 中等难度。

题目描述

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定有序数组: [-10,-3,0,5,9],

一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

思路

对于这个问题或者 给定一个二叉搜索树,将其改为平衡(后面会讲) 基本思路都是一样的。

题目的要求是将有序数组转化为:

  • 高度平衡的二叉树
  • 二叉搜索树

由于平衡二叉树是左右两个子树的高度差的绝对值不超过 1。因此一种简单的方法是**选择中点作为根节点,根节点左侧的作为左子树,右侧的作为右子树即可。**原因很简单,这样分配可以保证左右子树的节点数目差不超过 1。因此高度差自然也不会超过 1 了。

上面的操作同时也满足了二叉搜索树,原因就是题目给的数组是有序的。

你也可以选择别的数作为根节点,而不是中点,这也可以看出答案是不唯一的。

代码

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        if not nums: return None
        mid = (len(nums) - 1) // 2
        root = TreeNode(nums[mid])
        root.left = self.sortedArrayToBST(nums[:mid])
        root.right = self.sortedArrayToBST(nums[mid + 1:])
        return root

复杂度分析

  • 时间复杂度:由于每个节点最多被访问一次,因此总的时间复杂度为 O ( N ) O(N) O(N),其中 N N N 为数组长度。
  • 空间复杂度:由于使用了递归,这里的空间复杂度的瓶颈在栈空间,因此空间复杂度为 O ( h ) O(h) O(h),其中 h h h 为树的高度。同时由于是平衡二叉树,因此 h h h 就是 l o g N log N logN

109. 有序链表转换二叉搜索树(中等)

题目描述

`给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

思路

和 108 思路一样。 不同的是数据结构的不同,因此我们需要关注的是链表和数组的操作差异。

在这里插入图片描述
在这里插入图片描述

代码

var sortedListToBST = function (head) {
  if (!head) return null;
  return dfs(head, null);
};

function dfs(head, tail) {
  if (head == tail) return null;
  let fast = head;
  let slow = head;
  while (fast != tail && fast.next != tail) {
    fast = fast.next.next;
    slow = slow.next;
  }
  let root = new TreeNode(slow.val);
  root.left = dfs(head, slow);
  root.right = dfs(slow.next, tail);
  return root;
}

Java Code:

class Solution {
  public TreeNode sortedListToBST(ListNode head) {
      if(head == null) return null;
      return dfs(head,null);
  }
  private TreeNode dfs(ListNode head, ListNode tail){
      if(head == tail) return null;
      ListNode fast = head, slow = head;
      while(fast != tail && fast.next != tail){
          fast = fast.next.next;
          slow = slow.next;
      }
      TreeNode root = new TreeNode(slow.val);
      root.left = dfs(head, slow);
      root.right = dfs(slow.next, tail);
      return root;
  }
}

在这里插入图片描述
时间复杂度稍微困难一点点。之前西法在先导篇给大家说过:如果有递归那就是:递归树的节点数 * 递归函数内部的基础操作数。而这句话的前提是所有递归函数内部的基本操作数是一样的,这样才能直接乘。而这里递归函数的基本操作数不一样。

不过我们发现递归树内部每一层的基本操作数都是固定的, 为啥固定已经在图上给大家算出来了。因此总的空间复杂度其实可以通过递归深度 * 每一层基础操作数计算得出,也就是 n l o g n nlogn nlogn。 类似的技巧可以用于归并排序的复杂度分析中。

另外大家也直接可以通过公式推导得出。对于这道题来说,设基本操作数 T(n),那么就有 T(n) = T(n/2) * 2 + n/2,推导出来 T(n) 大概是 nlogn。这应该高中的知识。 具体推导过程如下:
在这里插入图片描述

1382. 将二叉搜索树变平衡(中等)

题目描述

给你一棵二叉搜索树,请你返回一棵 平衡后 的二叉搜索树,新生成的树应该与原来的树有着相同的节点值。

如果一棵二叉搜索树中,每个节点的两棵子树高度差不超过 1 ,我们就称这棵二叉搜索树是 平衡的 。

如果有多种构造方法,请你返回任意一种。

 

示例:

在这里插入图片描述


输入:root = [1,null,2,null,3,null,4,null,null]
输出:[2,1,3,null,null,null,4]
解释:这不是唯一的正确答案,[3,1,4,null,2,null,null] 也是一个可行的构造方案。
 

提示:

树节点的数目在 110^4 之间。
树节点的值互不相同,且在 110^5 之间。

思路

由于二叉搜索树的中序遍历是一个有序数组,因此问题很容易就转化为 108. 将有序数组转换为二叉搜索树(简单)。

代码

代码支持: Python3
Python3 Code:

class Solution:
    def inorder(self, node):
        if not node: return []
        return self.inorder(node.left) + [node.val] + self.inorder(node.right)
    def balanceBST(self, root: TreeNode) -> TreeNode:
        nums = self.inorder(root)
        def dfs(start, end):
            if start == end: return TreeNode(nums[start])
            if start > end: return None
            mid = (start + end) // 2
            root = TreeNode(nums[mid])
            root.left = dfs(start, mid - 1)
            root.right = dfs(mid + 1, end)
            return root
        return dfs(0, len(nums) - 1)

在这里插入图片描述

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

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

相关文章

一文搞懂linux的proc文件

目录 proc文件夹是干嘛用&#xff1f; proc下都有什么系统信息? /proc/bus /proc/buddyinfo /proc/cgroups /proc/cmdline /proc/consoles /proc/cpuinfo /proc/crypto /proc/devices /proc/diskstats /proc/execdomains /proc/fb /proc/filesystems …

JVM 体系结构

JVM: 跨平台语言 需要不同语言由自己编译器&#xff0c;生成符合 JSR-292 JVM规范的字节码文件&#xff0c;即可在 Java 虚拟机中运行 多语言混合编程: Java 平台上的多语言混合编程正成为主流&#xff0c;通过特定领域的语言去解决特定领域的问题是当前软件开发应对日趋复杂…

服务攻防-数据库安全-InfluxdbH2databaseCouchDBElasticSearch数据库漏洞复现

目录 一、Influxdb-未授权访问-Jwt 验证不当 1、Infuxdb简介 2、安全问题 3、漏洞复现 二、H2database-未授权访问-配置不当 1、H2database简介 2、安全问题 3、漏洞复现 三、CouchDB-权限绕过配合RCE-漏洞 1、CouchDB简介 2、安全问题 3、漏洞复现 四 、Elast…

《程序员面试金典(第6版)》面试题 16.15. 珠玑妙算

题目描述 珠玑妙算游戏&#xff08;the game of master mind&#xff09;的玩法如下。 计算机有4个槽&#xff0c;每个槽放一个球&#xff0c;颜色可能是红色&#xff08;R&#xff09;、黄色&#xff08;Y&#xff09;、绿色&#xff08;G&#xff09;或蓝色&#xff08;B&…

为什么我选择订阅ChatGPT Plus计划?

自从ChatGPT诞生以来&#xff0c;它的强大功能和表现一直备受好评。作为一个长期使用者&#xff0c;我一直对其性能和智能感到惊叹。最近&#xff0c;我决定升级我的用户体验&#xff0c;订阅了ChatGPT Plus计划。在这篇博客中&#xff0c;我将向您详细介绍ChatGPT Plus的优势和…

c语言那些有趣的事 -- 猜数字游戏

&#x1f4d5;博主介绍&#xff1a;目前大一正在学习c语言&#xff0c;数据结构&#xff0c;计算机网络。 c语言学习&#xff0c;是为了更好的学习其他的编程语言&#xff0c;C语言是母体语言&#xff0c;是人机交互接近底层的桥梁。 本章用循环去写一些题目。 让我们开启c语言…

细谈抽象类

目录 抽象类 1.抽象类是被abstract修饰的类 2.抽象类中的抽象方法 3.抽象类中可以有和普通类一样的成员变量和成员方法 4.抽象类不能被实例化 5.那么抽象类不能被实例化要它有何用&#xff1f;&#xff1f;&#xff1f; 6.注意&#xff1a; 抽象类 如果一个类中没有包含足…

基于Open3D的点云处理4-旋转、平移、缩放

三维变换主要包括&#xff1a;平移、旋转、缩放 在open3d中&#xff0c;针对三维对象的变换主要有translate、rotate、scale和transform • Translate 平移 • Rotate 旋转 • Scale 缩放 • Transform 变换矩阵&#xff08;4*4&#xff09; mesh_tx mesh.translate((1.5, …

昆山杜克大学首届毕业生就业情况

昆山杜克大学本科教育以通识博雅课程和跨学科教育为主要特色&#xff0c;倡导文理兼修&#xff0c;并以研究为导向。所有学生入学时不分专业&#xff0c;他们充分地自由选课探索之后&#xff0c;于大二结束之前选择最适合自己的专业。首届毕业生分布于以下12个专业。 教育理念是…

《SQLi-Labs》03. Less 11~15

sqli Less-11知识点题解 Less-12题解 Less-13题解 Less-14题解 Less-15知识点题解 sqli。开启新坑。 Less-11 知识点 第十一关页面发生了变化&#xff0c;是账户登录页面。那么注入点在输入框。 前十关使用的是 get 请求&#xff0c;参数都体现在 url 上&#xff0c;而十一关…

测试2:基础

目录 1.软件测试的生命周期 2.描述BUG 3.定义bug的级别 1.Blocker(崩溃) 2.Critical(严重) 3、Major&#xff08;一般&#xff09;&#xff1a; 4、Minor&#xff08;次要&#xff09;&#xff1a; 4.BUG的生命周期 1.软件测试的生命周期 需求分析,测试计划,测试设计,测…

实施CRM目标有哪几步?如何制定CRM目标?

在当今竞争激烈的商业环境中&#xff0c;与客户建立持久的关系是企业重要的工作。CRM客户管理系统能有效帮助企业管理优化流程、管理客户&#xff0c;提高销售成功率&#xff0c;推动收入增长。那么您了解如何实施CRM吗&#xff1f;下面说说实施CRM目标是什么&#xff0c;如何设…

Python小姿势 - # 字典(Dictionary)

字典&#xff08;Dictionary&#xff09; 字典是另一种可变容器模型&#xff0c;且可存储任意类型对象。 字典的每个键值 keyvalue 对用冒号 : 分割&#xff0c;每个对之间用逗号 , 分割&#xff0c;整个字典包括在花括号 {} 中 ,格式如下所示&#xff1a; d {key1 : value1, …

CSDN 周赛 50 期

CSDN 周赛 50 期 1、题目名称&#xff1a;订班服2、题目名称&#xff1a;异或和3、题目名称&#xff1a;零钱兑换4、题目名称&#xff1a;小艺照镜子小结 1、题目名称&#xff1a;订班服 小A班级订班服了&#xff01; 可是小A是个小糊涂鬼&#xff0c;整错了好多人的衣服的大小…

2022年NOC大赛编程马拉松赛道复赛图形化高年级A卷-正式卷,包含答案

目录 单选题: 多选题: 编程题: 下载打印文档做题: 2022年NOC大赛编程马拉松赛道复赛图形化高年级A卷-正式卷,包含答案 单选题:<

搭建Linux依赖环境

目录 1、jdk&#xff08;基于yum进行安装 &#xff09; 2、Tomcat &#xff08;手动下载安装&#xff09; 3、MariaDB&#xff08;基于yum进行安装&#xff09; 安装 启动 测试连接 1、jdk&#xff08;基于yum进行安装 &#xff09; 可以使用yum list | grep [关键词…

js基础1

一.js中的变量 a.var,let ,const的异同 1.var var在不进行初始化的条件下的值为undefined,它的作用域是函数作用域&#xff0c;在使用var在函数的内部定义一个变量的时候&#xff0c;意味着该变量在退出前进行销毁。并且它可以进行变量提升。 例子&#xff1a; function f…

操作系统概述(一、并发)

系列文章目录 文章目录 系列文章目录前言定义 一、操作系统发展史1940s的程序1950s的计算机1960s的计算机1970s 基本和现代一样了 others 二、程序状态模型从不同视角看程序&#xff1a; 操作系统上的程序 三、线程库四、程序并发五、自旋锁与互斥锁的实现自旋锁的使用场景 六、…

21 brk 的初始化

前言 这个问题是 衍生自 malloc 的问题的调试 malloc 虚拟内存分配的调试(1) malloc 虚拟内存分配的调试(2) 假设我们使用 gdb 或者 gdbserver 启动调试的该测试用例对应的可执行程序 我们可以观察到的现象是 p1, p2, p3 的地址是固定的, 均是类似于 elf 中最大的虚拟地…

基于vue3+pinia2仿ChatGPT聊天实例|vite4.x仿chatgpt界面

使用vue3pinia2开发仿制chatgpt界面聊天实例Vue3-Chatgpt 基于Vue3.xPinia2VueRouterVue3-Markdown等技术构建仿ChatGPT网页端聊天程序。支持经典分栏界面布局、light/dark模式、全屏半屏显示、Markdown语法解析、侧边栏隐藏等功能。 技术框架 编辑工具&#xff1a;Cursor框架…