代码随想录-Day23

news2024/9/21 18:41:31

669. 修剪二叉搜索树

在这里插入图片描述

方法一:递归

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) {
            return null;
        }
        if (root.val < low) {
            return trimBST(root.right, low, high);
        } else if (root.val > high) {
            return trimBST(root.left, low, high);
        } else {
            root.left = trimBST(root.left, low, high);
            root.right = trimBST(root.right, low, high);
            return root;
        }
    }
}

这段代码定义了一个名为 Solution 的类,其中包含一个方法 trimBST,用于修剪(裁剪)给定二叉搜索树(BST)中的节点,使得所有节点的值在指定的区间 [low, high] 内。修剪操作应当保持二叉搜索树的性质。以下是代码逻辑的详细解析:

  1. 基本情况处理:首先检查根节点 root 是否为空。如果为空,直接返回 null,因为没有节点需要修剪。

  2. 节点值处理

    • 如果当前节点 root 的值 root.val 小于 low,说明当前节点及其左子树都不可能在保留范围内,因此直接递归地对右子树 root.right 调用 trimBST 方法,并返回结果作为新的根节点。这一步相当于“跳过”当前节点及其左子树。
    • 如果当前节点 root 的值 root.val 大于 high,说明当前节点及其右子树都不可能在保留范围内,因此直接递归地对左子树 root.left 调用 trimBST 方法,并返回结果作为新的根节点。这一步相当于“跳过”当前节点及其右子树。
    • 如果当前节点的值满足 low <= root.val <= high,说明当前节点值在指定区间内,需要保留。此时,递归地对左右子树进行修剪,并保持当前节点作为修剪后子树的根节点。
  3. 递归修剪子树:当当前节点值符合条件需要保留时,分别对左子树 root.left 和右子树 root.right 递归调用 trimBST 方法,以确保整个子树都被正确修剪。

  4. 返回处理后的节点:经过上述处理后,直接返回当前处理过的节点 root,作为修剪后子树的根。递归过程中,这个返回值会被上一层调用用来构建整个修剪后的BST。

通过这样的递归逻辑,trimBST 方法能够从根节点开始,逐步构建出只包含值在 [low, high] 范围内的二叉搜索树,并保持BST的性质。不在范围内的节点及其子树都会被“剪掉”,从而实现高效的修剪操作。

方法二:迭代

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        while (root != null && (root.val < low || root.val > high)) {
            if (root.val < low) {
                root = root.right;
            } else {
                root = root.left;
            }
        }
        if (root == null) {
            return null;
        }
        for (TreeNode node = root; node.left != null; ) {
            if (node.left.val < low) {
                node.left = node.left.right;
            } else {
                node = node.left;
            }
        }
        for (TreeNode node = root; node.right != null; ) {
            if (node.right.val > high) {
                node.right = node.right.left;
            } else {
                node = node.right;
            }
        }
        return root;
    }
}

这段代码提供了另一种实现方式,使用迭代方法来修剪二叉搜索树(BST),使其所有节点的值落在指定区间 [low, high] 内。相较于递归方法,迭代方法直接利用循环进行遍历和修剪。以下是代码逻辑的详细解析:

  1. 初始化:首先,代码通过一个 while 循环找到BST的第一个(最左边的)落在指定区间 [low, high] 内的节点作为新的根节点。如果根节点 root 的值小于 low,则向右移动(因为BST的性质保证了所有左子节点的值都小于根节点,所以要找大于等于 low 的节点,只能往右走);如果根节点的值大于 high,则向左移动。如果整个树的所有节点都不在区间内,最终 root 会变成 null,直接返回 null

  2. 修剪左子树:接下来,使用一个 for 循环来修剪根节点的左子树。循环的条件是当前节点的左子节点不为空。如果左子节点的值小于 low,说明整个左子树都不在指定区间内,直接将当前节点的左子节点更新为其左子节点的右子节点(跳过整个左子树的左部分);否则,将当前节点更新为其左子节点,继续检查更左的节点。

  3. 修剪右子树:随后,再使用一个类似的 for 循环来修剪根节点的右子树。循环的条件是当前节点的右子节点不为空。如果右子节点的值大于 high,说明整个右子树的右部分都不在指定区间内,直接将当前节点的右子节点更新为其右子节点的左子节点(跳过整个右子树的右部分);否则,将当前节点更新为其右子节点,继续检查更右的节点。

  4. 返回修剪后的根节点:经过上述两步修剪后,根节点及其左右子树都已经满足条件,直接返回 root 作为修剪后的二叉搜索树的根。

这种迭代方法同样保持了BST的性质,并且在处理每个节点时都是常量时间复杂度,总体时间复杂度为O(N),其中N为树中的节点数,空间复杂度为O(1),因为它只使用了固定数量的指针变量。

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

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵
平衡二叉搜索树。

方法一:中序遍历,总是选择中间位置左边的数字作为根节点

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return helper(nums, 0, nums.length - 1);
    }

    public TreeNode helper(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }

        // 总是选择中间位置左边的数字作为根节点
        int mid = (left + right) / 2;

        TreeNode root = new TreeNode(nums[mid]);
        root.left = helper(nums, left, mid - 1);
        root.right = helper(nums, mid + 1, right);
        return root;
    }
}

这段代码定义了一个名为 Solution 的类,其中包含两个方法,用于将一个有序数组(升序)转换成一棵高度平衡的二叉搜索树(BST)。二叉搜索树的特性是左子树所有节点的值小于根节点的值,右子树所有节点的值大于根节点的值,且每个节点的左、右子树也分别是BST。下面是代码的详细解析:

  1. sortedArrayToBST(int[] nums) 方法:这是主要的接口方法,接收一个有序数组 nums 作为参数,然后调用辅助方法 helper 来完成转换工作,最终返回构建好的BST的根节点。

  2. helper(int[] nums, int left, int right) 方法:这是一个递归辅助方法,用于实际构建BST。

    • 输入参数nums 是原始有序数组,leftright 分别表示当前子数组的左右边界索引。
    • 终止条件:如果 left > right,表示当前子数组为空,没有节点可构建,因此返回 null
    • 选择根节点:为了构建高度平衡的BST,总是选择中间位置(或中间偏左,这里取中间下标 mid = (left + right) / 2)的元素作为根节点的值,这样做可以保证树尽量平衡。注意,当 leftright 为偶数时,mid 实际上取的是中间两个数中左边的那个。
    • 递归构建左右子树:以 mid 为界,分别对左半部分 [left, mid - 1] 和右半部分 [mid + 1, right] 递归调用 helper 方法,构建当前节点的左子树和右子树。
    • 返回根节点:构建好左右子树后,返回当前子树的根节点。

通过这样的递归划分,每个子数组都会被处理成一个高度平衡的BST子树,最终整个数组转换成了一棵高度平衡的二叉搜索树。这种方法充分利用了有序数组的特性,保证了构建的BST不仅是正确的,而且高度平衡,提高了树的查询效率。

方法二:中序遍历,总是选择中间位置右边的数字作为根节点

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return helper(nums, 0, nums.length - 1);
    }

    public TreeNode helper(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }

        // 总是选择中间位置右边的数字作为根节点
        int mid = (left + right + 1) / 2;

        TreeNode root = new TreeNode(nums[mid]);
        root.left = helper(nums, left, mid - 1);
        root.right = helper(nums, mid + 1, right);
        return root;
    }
}

这段代码与之前提供的解决方案非常相似,都是将一个有序数组(升序)转换为一棵高度平衡的二叉搜索树(BST)。主要区别在于选取中间元素的方式:之前的解决方案选取中间位置左边的数字作为根节点,而这里的代码选择的是中间位置右边的数字。下面是代码解析:

  1. sortedArrayToBST(int[] nums) 方法:此方法作为接口,接收一个有序数组 nums,然后调用辅助方法 helper 来构建平衡BST,并返回根节点。

  2. helper(int[] nums, int left, int right) 方法:这是一个递归辅助方法,用于递归构建BST。

    • 输入参数nums 是原始有序数组,leftright 分别表示当前考虑构建子树的数组范围。
    • 终止条件:当 left > right 时,表示当前区间为空,无需构建节点,直接返回 null
    • 选择根节点:与之前版本不同,这里通过 (left + right + 1) / 2 计算中间索引,目的是选择区间的中间位置右边的数作为根节点。这确保了当数组长度为奇数时,中间值取右侧;偶数时,同样偏向取右侧的值作为根。
    • 递归构建子树:基于选定的根节点值,分别对左半区间 [left, mid - 1] 和右半区间 [mid + 1, right] 递归调用 helper 方法,构建当前节点的左子树和右子树。
    • 返回根节点:构建完左右子树后,返回当前子树的根节点。

通过这样的递归过程,整个数组被均衡地分割并构建为一棵高度平衡的BST,其中每个节点的值都来自数组中的一个位置,且树保持了BST的性质(左子树所有节点值小于根节点值,右子树所有节点值大于根节点值)。选择中间偏右的元素作为根节点是实现平衡的一种方式,虽不如选取正中间那样绝对平衡,但在大多数情况下能保持较好的平衡性。

方法三:中序遍历,选择任意一个中间位置数字作为根节点

class Solution {
    Random rand = new Random();

    public TreeNode sortedArrayToBST(int[] nums) {
        return helper(nums, 0, nums.length - 1);
    }

    public TreeNode helper(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }

        // 选择任意一个中间位置数字作为根节点
        int mid = (left + right + rand.nextInt(2)) / 2;

        TreeNode root = new TreeNode(nums[mid]);
        root.left = helper(nums, left, mid - 1);
        root.right = helper(nums, mid + 1, right);
        return root;
    }
}

这段代码依然致力于将一个有序数组(升序)转换为一棵高度平衡的二叉搜索树(BST),但与之前的实现有所不同,它在选择中间元素作为根节点时引入了随机性,以提高算法在特定输入下的性能表现。下面是代码的详细解析:

  1. 类成员变量:定义了一个 Random 类型的成员变量 rand,用于生成随机数。

  2. sortedArrayToBST(int[] nums) 方法:此方法与之前的实现相同,作为对外接口,接收有序数组并调用 helper 方法构建BST。

  3. helper(int[] nums, int left, int right) 方法:这个递归辅助方法负责实际的转换工作,其参数含义也保持一致。不同之处在于如何选择中间元素:

    • 随机选择中间位置:这里使用公式 (left + right + rand.nextInt(2)) / 2 来确定中间位置的索引。rand.nextInt(2) 会返回0或1,加上 leftright 后除以2,实质上会在左侧的中间位置和右侧的中间位置之间随机选择一个索引作为根节点。这种方法在理论上可以避免在特定输入数据下构造出极端不平衡的BST,比如当有序数组本身就是近乎有序的情况下,传统的总是选择中间位置作为根节点的方法可能导致构造出来的BST极度倾斜。通过随机化选择,可以使得构造的BST在统计学意义上更加平衡,提高树的操作效率,如查找、插入等。
  4. 构建左右子树:与之前的实现相同,根据选定的中间位置索引,递归地构建当前节点的左子树和右子树。

通过这种方式,尽管每次运行时可能生成不同的BST(因为根节点的选择是随机的),但整体上仍然能保证构建出的BST高度平衡,同时在一定程度上优化了在特定输入下的性能表现,特别是对于那些可能导致递归方法偏向构建非平衡树的特殊排序数组。

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

反序中序遍历

class Solution {
    int sum = 0;

    public TreeNode convertBST(TreeNode root) {
        if (root != null) {
            convertBST(root.right);
            sum += root.val;
            root.val = sum;
            convertBST(root.left);
        }
        return root;
    }
}

这段代码定义了一个名为 Solution 的类,其中包含一个方法 convertBST,该方法旨在将一个二叉搜索树(BST)转换成一个累加树。累加树是一种特殊的二叉树,其中每个节点的值等于原来的节点值加上所有大于它的节点值(在原BST中)。具体实现细节如下:

  • 类成员变量:

    • sum:这是一个整型成员变量,初始化为0,用于在遍历过程中累加节点值。
  • convertBST(TreeNode root) 方法

    • 输入参数:root 是二叉搜索树的根节点。
    • 返回值:返回转换后的二叉搜索树的根节点,现在它变成了一棵累加树。

方法内部逻辑遵循后序遍历的顺序(右子树 -> 根节点 -> 左子树),这是解决此类问题的关键,原因如下:

  1. 先遍历右子树:由于BST的性质(左子树的所有节点小于根节点,右子树的所有节点大于根节点),先访问右子树意味着我们从最大的节点开始累加,这符合累加树的要求。
  2. 累加当前节点值:在访问完当前节点的右子树后,将当前节点的值与已累加的值相加,然后更新当前节点的值。
  3. 遍历左子树:最后遍历左子树,这样在访问左子树的每个节点时,它们都会得到已经更新过的父节点及父节点右边所有节点的累加和。

通过这样的递归过程,整个BST被转换成了累加树,且每个节点的值都正确反映了累加的规则。最后,该方法返回转换后的树的根节点。

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

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

相关文章

爪哇,我初学乍道

>>上一篇&#xff08;学校上课&#xff0c;是耽误我学习了。。&#xff09; 2016年9月&#xff0c;我大二了。 自从我发现上课会耽误我学习&#xff0c;只要我认为不影响我期末学分的&#xff0c;我就逃课了。 绝大多数课都是要签到的&#xff0c;有的是老师突击喊名字…

YOLO-10更快、更强

YOLO-10简介 主要贡献&#xff1a; 无NMS的一致双分配 YOLOv10提出了一种通过双标签分配而不用非极大值抑制NMS的策略。这种方法结合了一对多和一对一分配策略的优势&#xff0c;提高了效率并保持了性能。 高效的网络设计 轻量化分类头&#xff1a;在不显著影响性能的情况下&a…

618数码产品怎么选?四大必看推荐,自费无广测评

6.18盛宴即将开启&#xff0c;你是否已摩拳擦掌&#xff0c;准备在电商海洋中乘风破浪&#xff1f;然而&#xff0c;在繁多的商品和错综复杂的优惠面前&#xff0c;你是否感到些许迷茫&#xff1f;团团这位网购小能手&#xff0c;特地为大家梳理了一份精选购物清单。这些宝贝不…

搭建YOLOv10环境 训练+推理+模型评估

文章目录 前言一、环境搭建必要环境1. 创建yolov10虚拟环境2. 下载pytorch (pytorch版本>1.8)3. 下载YOLOv10源码4. 安装所需要的依赖包 二、推理测试1. 将如下代码复制到ultralytics文件夹同级目录下并运行 即可得到推理结果2. 关键参数 三、训练及评估1. 数据结构介绍2. 配…

2024.05.29学习记录

1、css面经复习 2、代码随想录二刷 3、rosebush upload组件初步完成

【芯片验证方法】

术语——中文术语 大陆与台湾的一些术语存在差别&#xff1a; 验证常用的英语术语&#xff1a; 验证&#xff1a;尽量模拟实际应用场景&#xff0c;比对芯片的所需要的目标功能和实现的功能 影响验证的要素&#xff1a;应用场景、目标功能、比对应用场景、目标功能&#xff…

OpenAI新模型开始训练!GPT6?

国内可用潘多拉镜像站GPT-4o、GPT-4&#xff08;更多信息请加Q群865143845&#xff09;: 站点&#xff1a;https://xgpt4.ai0.cn/ OpenAI 官网 28 日发文称&#xff0c;新模型已经开始训练&#xff01; 一、新模型开始训练 原话&#xff1a;OpenAI has recently begun training…

性能大爆炸!为你的Matomo换一个高性能的环境!

随着我的 Matomo 越来越大&#xff0c;功能需求的增多&#xff0c;插件也变得越来越多&#xff0c;使用传统的LNMP架构或者LAMP架构都会发现性能正在急剧下级&#xff0c;为此&#xff0c;我们发现了使用FrankenPHP&#xff08;以下简称FPHP&#xff09;的方案 首先&#xff0…

【本地运行chatgpt-web】启动前端项目和service服务端项目,也是使用nodejs进行开发的。两个都运行成功才可以使用!

1&#xff0c;启动web界面 https://github.com/Chanzhaoyu/chatgpt-web#node https://nodejs.org/en/download/package-manager # 使用nvm 安装最新的 20 版本。 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source /root/.bashrc n…

攀爬二叉树,发现新的美

二叉树 什么是二叉树? 二叉树的基础概念? 性质? 问题? 文章目录 二叉树一、二叉树的概念(一)认识二叉树(二)二叉树的性质 二、遍历二叉树1.前序遍历2.中序遍历3.后序遍历4.层序遍历 三丶创建二叉树总结 一、二叉树的概念 (一)认识二叉树 二叉树是一种非线性的数据结构,…

一篇文章讲透排序算法之快速排序

前言 本篇博客难度较高&#xff0c;建议在学习过程中先阅读一遍思路、浏览一遍动图&#xff0c;之后研究代码&#xff0c;之后仔细体会思路、体会动图。之后再自己进行实现。 一.快排介绍与思想 快速排序相当于一个对冒泡排序的优化&#xff0c;其大体思路是先在文中选取一个…

鸿蒙课程培训 | 讯方技术与鸿蒙生态服务公司签约,成为鸿蒙钻石服务商

3月15日&#xff0c;深圳市讯方技术股份有限公司与鸿蒙生态服务公司签署合作协议&#xff0c;讯方技术成为鸿蒙钻石服务商&#xff0c;正式进军鸿蒙原生应用培训开发领域。讯方技术总裁刘国锋、副总经理刘铭皓、深圳区域总经理张松柏、深圳区域交付总监张梁出席签约仪式。 作…

基于51单片机的交通灯设计

一.硬件方案 本设计能模拟基本的交通控制系统&#xff0c;用红绿黄灯表示禁行&#xff0c;通行和等待的信号发生&#xff0c;还能进行倒计时显示。按键可以控制禁行、深夜模式、复位、东西通行、南北通行、时间加、时间减、切换等功能。共四个二位阴极数码管&#xff0c;东南西…

【busybox记录】【shell指令】unlink

目录 内容来源&#xff1a; 【GUN】【unlink】指令介绍 【busybox】【unlink】指令介绍 【linux】【unlink】指令介绍 使用示例&#xff1a; 删除文件 - 默认 常用组合指令&#xff1a; 指令不常用/组合用法还需继续挖掘&#xff1a; 内容来源&#xff1a; GUN &#x…

SpringCloud系列(31)--使用Hystrix进行服务降级

前言&#xff1a;在上一章节中我们创建了服务消费者模块&#xff0c;而本节内容则是使用Hystrix对服务进行服务降级处理。 1、首先我们先对服务提供者的服务进行服务降级处理 (1)修改cloud-provider-hystrix-payment8001子模块的PaymentServiceImpl类 注&#xff1a;HystrixP…

Hadoop3:MapReduce之简介、WordCount案例源码阅读、简单功能开发

一、概念 MapReduce是一个 分布式运算程序 的编程框架&#xff0c;是用户开发“基于 Hadoop的数据分析 应用”的核心框架。 MapReduce核心功能是将 用户编写的业务逻辑代码 和 自带默认组件 整合成一个完整的 分布式运算程序 &#xff0c;并发运行在一个 Hadoop集群上。 1、M…

软件架构设计属性之一:功能性属性浅析

引言 软件架构设计属性中的功能性属性是评估软件架构是否满足其预定功能需求的关键指标。功能性属性确保软件能够执行其设计中的任务&#xff0c;并提供所需的服务。以下是对软件架构设计中功能性属性的浅析&#xff1a; 一、定义 功能性属性是指软件系统所具备的功能特性&a…

怎么将3D模型转换立面图---模大狮模型网

在建筑设计、室内设计以及产品建模等领域&#xff0c;经常需要将3D模型转换为立面图以进行展示、分析或交流。立面图能够清晰地呈现物体的外观和结构&#xff0c;是设计和施工中不可或缺的一部分。 一、导出3D模型 首先&#xff0c;需要将3D模型导出为CAD软件能够识别的格式。…

如何配置才能连接远程服务器上的 redis server ?

文章目录 Intro修改点 Intro 以阿里云服为例。 首先&#xff0c;我在我买的阿里云服务器中以下载源码、手动编译的方式安装了 redis-server&#xff0c;操作流程见&#xff1a;Ubuntu redis 下载解压配置使用及密码管理 && 包管理工具联网安装。 接着&#xff0c;我…

(函数)颠倒字符串顺序(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <string.h>//声明颠倒函数; void reverse(char a[]) {//初始化变量值&#xff1b;int i, j;char t;//循环颠倒&#xff1b;for (i 0, j strl…