【算法思想·二叉搜索树】特性篇

news2024/11/25 6:51:59

本文参考labuladong算法笔记[二叉搜索树心法(特性篇) | labuladong 的算法笔记]

1、概述

首先,BST(binary search tree) 的特性大家应该都很熟悉了(详见基础知识章节的 二叉树基础):

1、对于 BST 的每一个节点 node,左子树节点的值都比 node 的值要小,右子树节点的值都比 node 的值大。

2、对于 BST 的每一个节点 node,它的左侧子树和右侧子树都是 BST。

二叉搜索树并不算复杂,但我觉得它可以算是数据结构领域的半壁江山,直接基于 BST 的数据结构有 AVL 树,红黑树等等,拥有了自平衡性质,可以提供 logN 级别的增删查改效率;还有 B+ 树,线段树等结构都是基于 BST 的思想来设计的。

从做算法题的角度来看 BST,除了它的定义,还有一个重要的性质:BST 的中序遍历结果是有序的(升序),反向中序遍历则是降序。

也就是说,如果输入一棵 BST,以下代码可以将 BST 中每个节点的值升序打印出来:

def traverse(root):
    if not root:
        return
    traverse(root.left)
    # 中序遍历代码位置
    print(root.val)
    traverse(root.right)

230. 寻找第 K 小的元素

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。

示例 1:

输入:root = [3,1,4,null,2], k = 1
输出:1

示例 2:

输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3

提示:

  • 树中的节点数为 n 。
  • 1 <= k <= n <= 104
  • 0 <= Node.val <= 104

进阶:如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化算法?

这个需求很常见吧,一个直接的思路就是升序排序,然后找第 k 个元素呗。BST 的中序遍历其实就是升序排序的结果,找第 k 个元素肯定不是什么难事。

【python】

class Solution:
    '''
    思路:
        1、利用BST特性,中序遍历该root,用列表承接每个节点,直到列表长度为k则返回最后一个元素
    '''
    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        # res用于承接遍历结果
        self.res = []
        self.traverse(root, k)
        return self.res[k-1]

    def traverse(self, node, k):
        if not node:
            return

        self.traverse(node.left, k)
        self.res.append(node.val)
        if len(self.res) == k:
            return
        self.traverse(node.right, k)

538. 把二叉搜索树转换为累加树 | 力扣  | LeetCode  |

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

  • 节点的左子树仅包含键 小于 节点键的节点。
  • 节点的右子树仅包含键 大于 节点键的节点。
  • 左右子树也必须是二叉搜索树。

注意:本题和 1038: . - 力扣(LeetCode) 相同

示例 1:

输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

示例 2:

输入:root = [0,null,1]
输出:[1,null,1]

示例 3:

输入:root = [1,0,2]
输出:[3,3,2]

示例 4:

输入:root = [3,2,4,1]
输出:[7,9,4,10]

提示:

  • 树中的节点数介于 0 和 104 之间。
  • 每个节点的值介于 -104 和 104 之间。
  • 树中的所有值 互不相同 。
  • 给定的树为二叉搜索树。

题目应该不难理解,比如图中的节点 5,转化成累加树的话,比 5 大的节点有 6,7,8,加上 5 本身,所以累加树上这个节点的值应该是 5+6+7+8=26。

我们需要把 BST 转化成累加树,函数签名如下:

def convertBST(root: TreeNode) -> TreeNode:

【思路】

按照二叉树的通用思路,需要思考每个节点应该做什么,但是这道题上很难想到什么思路。

BST 的每个节点左小右大,这似乎是一个有用的信息,既然累加和是计算大于等于当前值的所有元素之和,那么每个节点都去计算右子树的和,不就行了吗?

这是不行的。对于一个节点来说,确实右子树都是比它大的元素,但问题是它的父节点也可能是比它大的元素呀?这个没法确定的,我们又没有触达父节点的指针,所以二叉树的通用思路在这里用不了。

此路不通,我们不妨换一个思路,还是利用 BST 的中序遍历特性

刚才我们说了 BST 的中序遍历代码可以升序打印节点的值,那如果我想降序打印节点的值怎么办?

很简单,只要把递归顺序改一下,先遍历右子树,后遍历左子树就行了

class Solution:
        def __init__(self):
            # 记录累加和
            self.sum = 0
            
        def convertBST(self, root):
            self.traverse(root)
            return root

        def traverse(self, root):
            if root is None:
                return
            self.traverse(root.right)
            # 维护累加和
            self.sum += root.val
            # 将 BST 转化成累加树
            root.val = self.sum
            self.traverse(root.left)

这道题就解决了,核心还是 BST 的中序遍历特性,只不过我们修改了递归顺序,降序遍历 BST 的元素值,从而契合题目累加树的要求。

简单总结下吧,BST 相关的问题,要么利用 BST 左小右大的特性提升算法效率,要么利用中序遍历的特性满足题目的要求,也就这么些事儿吧。

2、总结

所谓BST的特性,关键就是:

1、BST本身特性,左孩子值 < 父节点值 < 右孩子值 

2、基于1,BST中序遍历(左中右)结果是升序排列节点值,反向中序遍历(右中左)则是降序排列

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

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

相关文章

【QGC】把QGroundControl地面站添加到Ubuntu侧边菜单栏启动

把QGroundControl地面站添加到Ubuntu侧边菜单栏启动 简介准备工作步骤 1: 创建 Desktop Entry 文件步骤 2: 编辑 Desktop Entry 文件步骤 3: 刷新应用程序菜单步骤 4: 将 QGroundControl 固定到侧边栏 环境&#xff1a; Ubuntu &#xff1a;20.04 LTS 简介 QGroundControl 是…

[综述笔记]Federated learning for medical image analysis: A survey

论文网址&#xff1a;Federated learning for medical image analysis: A survey - ScienceDirect 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&…

C++ Primer Plus(速记版)-基本语言

序章 快速入门 初窥输入/输出 C 并没有直接定义进行输入或输出(I/O)的任何语句&#xff0c;这种功能是由标准库提供的。 本书的大多数例子都使用了处理格式化输入和输出的 iostream 库。 iostream 库的基础是两种命名为 istream 和 ostream 的类型&#xff0c;分别表示输入流和…

卷积神经网络-经典分类网络结构(LetNet-5,AlexNet)

目录 一&#xff1a;LeNet-5解析 1.网络结构 输入层&#xff1a; 1.conv1&#xff1a; 2.pool1层&#xff1a; 3.conv2&#xff1a; 4.pool2&#xff1a; 5.fc3&#xff0c;fc4&#xff1a; 6.output层: 2.参数形状 二&#xff1a;AlexNet 1层&#xff1a; 2层&am…

招生管理|基于Java+vue的招生管理系统(源码+数据库+文档)

招生管理|学生管理系统|高校招生管理 目录 基于Javavue的招生管理系统 一、前言 二、系统设计 三、系统功能设计 系统功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|…

什么是OAuth 2.0?OAuth 2.0的工作流程是什么?与OAuth 1.0有哪些区别?

在浏览网页时&#xff0c;你肯定会遇到允许你使用社交媒体账户登录的网站。此功能一般是使用流行的OAuth 2.0框架构建的。OAuth 2.0是对OAuth 1.0的彻底重写&#xff0c;OAuth 2.0与OAuth 1.0或1.1不向后兼容。 1. OAuth产生背景 为了更好的理解OAuth&#xff0c;我们假设有如…

CAN总线-STM32上CAN外设

1.STM32 CAN外设简介 2.CAN网拓扑结构 3.CAN收发器电路 4.CAN框图 5.CAN基本结构 6.发送过程 7.接收过程 8.发送和接收配置位 9.标识过滤器&#xff08;重点&#xff09; 这里的FBMX模式设置的列表模式&#xff1a;你在列表中输入你想要的报文ID&#xff0c;不在你列表中的ID屏…

css grid布局属性详解

Grid布局 前言一、认识Grid1.1容器和项目1.2行和列1.3单元格和网格线 二、容器属性2.1.grid-template-columns与grid-template-rows属性2.1.1 直接使用长度单位比如px2.1.2 使用百分比 %2.1.3 使用repeat函数2.1.4 按比例划分 fr 关键字2.1.5 自动填充 auto 关键字2.1.6 最大值…

c4d的重命名工具(支持模型和材质) 及 python窗口定义

不是我牛逼&#xff0c;是豆包牛逼&#xff01; 一个简化版的窗口 import c4d from c4d import guiclass MyDialog(gui.GeDialog):def __init__(self):super().__init__()self.SetTitle("My Dialog")def CreateLayout(self):# 设置对话框布局return Truemy_dialog …

C语言补习课番外篇——采样sin(x)

需求&#xff1a;让stm32的DAC输出正弦波形 分析&#xff1a;DAC的原理这里不作过多介绍。在[0.2π]的定义域内对sin(x)的值域进行采样&#xff0c;采样次数为256次&#xff1b;采样结果需要等比例缩放到0~4095的无符号数范围内&#xff0c;并且输出到一个SinFile.txt文本文档…

无敌C++大王养成篇一

1.命名空间 namespace c语⾔项⽬类似下⾯程序这样的命名冲突是普遍存在的问题&#xff0c;C引⼊namespace就是为了更好的解决 这样的问题 #include<stdio.h> //#include<stdlib.h>int rand 10;int main() {printf("%d\n",rand); }//运行时编译没有…

Grafana 可视化配置

Grafana 是什么 Grafana 是一个开源的可视化和监控工具&#xff0c;广泛用于查看和分析来自各种数据源的时间序列数据。它提供了一个灵活的仪表盘&#xff08;dashboard&#xff09;界面&#xff0c;用户可以通过它将数据源中的指标进行图表化展示和监控&#xff0c;帮助分析趋…

语音转文字工具全解析

无论是学生群体记录课堂笔记&#xff0c;职场人士整理会议纪要&#xff0c;还是自媒体创作者捕捉灵感火花&#xff0c;录音转文字软件都以其独特的便利性和高效性赢得了广泛的好评。今天&#xff0c;就让我们一起探索那些深受大家喜爱的录音转文字工具吧。 1.365在线转文字 链…

C++ | Leetcode C++题解之第397题整数替换

题目&#xff1a; 题解&#xff1a; class Solution { public:int integerReplacement(int n) {int ans 0;while (n ! 1) {if (n % 2 0) {ans;n / 2;}else if (n % 4 1) {ans 2;n / 2;}else {if (n 3) {ans 2;n 1;}else {ans 2;n n / 2 1;}}}return ans;} };

Window 本地启动Nacos

前言 本文帮助大家快速windows环境本地启动naco&#xff08;以版本2.2.3为例&#xff09; 进一步深入学习nacos推荐我的另外一篇文章&#xff1a; springCloud组件专题&#xff08;一&#xff09; --- Nacos_springcloud中的nacos如何使用-CSDN博客 ** 在本地启动nacos之前&…

C:字符函数与字符串函数-学习笔记

目录 1、字符分类函数 2、字符转换函数 3、字符串函数 4、strlen 函数的使用与模拟实现 4.1 strlen函数的使用 4.2 strlen函数的模拟实现 1、字符分类函数 C语言中有一系列的函数是专门做字符分类的&#xff0c;也就是一个字符是属于什么类型的字符的。 这些函数的使用都…

Vue(10)——自定义指令

自定义指令 自定义指令&#xff1a;可以封装一些dom操作&#xff0c;扩展额外功能。 全局注册-语法&#xff1a; Vue.directive(指令名,{ "inserted"(el){ inserted指指令所绑定的元素被添加到页面时自动调用 //可以对el标签扩展额外功能 el.focus() } }) 局部…

基于python+django+vue+MySQL的酒店推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】pythondjangovueMySQL的酒店推…

NLP中文本生成任务

文本生成任务 1.生成式任务2.自回归模型实现3.Encoder-Decoder结构3.1Attention机制出现3.2Attention思想3.3soft - Attention3.4hard - Attention3.5Teacher Forcing3.6详解Mask Attention3.6.1通过Mask控制训练方式 4.生成式任务评价指标5.生成式任务常见问题5.1采样策略5.2指…

深入解析Java内存模型:从堆到栈的全面剖析

在Java程序运行的背后&#xff0c;JVM&#xff08;Java Virtual Machine&#xff0c;Java虚拟机&#xff09;负责管理和分配内存。理解Java的内存模型&#xff08;Java Memory Model, JMM&#xff09;是编写高效、稳定程序的关键&#xff0c;尤其在并发编程中&#xff0c;内存管…