代码随想录DAY21 - 二叉树 - 08/20

news2024/9/20 13:11:03

目录

修建二叉搜索树

题干

思路和代码

递归法

迭代法

将有序数组转化为平衡二叉搜索树

题干

思路和代码

递归法

递归优化

迭代法

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

题干

思路和代码

递归法

迭代法


修建二叉搜索树

题干

题目:给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

说明:

  • 每个结点值非负数,0 <= Node.val <= 104

  • 树中每个节点的值都是 唯一 的

链接:. - 力扣(LeetCode)

思路和代码

先判断根节点是否在 [low, high] 的范围内,如果不是则删除,并从左右子树中找到新的根节点;如果是则递归修剪左右子树。

递归法
  • 递归参数和返回值:参数是传入的根节点,闭区间的最小边界 low、最大边界 high;返回值是修建过的新子树的根节点。

  • 递归结束的条件:当传入的节点为空,代表没有子树需要修建,返回空。

  • 递归顺序:前序遍历,先判断根节点是否在 [low, high] 的范围内,如果不是则删除,并从左右子树中找到新的根节点;如果是则递归修剪左右子树。

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if (root == nullptr) return nullptr;
        if (root->val < low){
            // 根结点包括根节点的左子树都要被删除,新的根节点应为修剪过的右子树
            root = trimBST(root->right,low,high);
        } else if (root->val > high){
            // 根结点包括根节点的右子树都要被删除,新的根节点应为修剪过的左子树
            root = trimBST(root->left,low,high);
        } else{
            // 根节点在 [low, high] 范围内,修剪左右子树
            if (root->left) root->left = trimBST(root->left,low,high);
            if (root->right) root->right = trimBST(root->right,low,high);
        }
        return root;
    }
};
迭代法

迭代法暂时不太理解思路,需要二刷的时候复盘。

将有序数组转化为平衡二叉搜索树

题干

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

链接:. - 力扣(LeetCode)

思路和代码

要让二叉搜索树平衡,也就是让左右子树的高度差尽量相同,即让左右子树的节点数目尽量相同。那么只需每次建树时让序列中点作为根节点,再让左右子树建树。

递归法
  • 递归参数和返回值:参数即传入的序列数组,返回值是根据序列构建好的二叉树的根节点,需要将返回值传递给上层父节点。

  • 递归结束的条件:当传入的序列数组为空,返回空节点。

  • 递归顺序:前序遍历,每次让序列中点作为根节点,再递归构建左右子树。

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        int size = nums.size();
        if (size == 0) return nullptr;
        TreeNode* root = new TreeNode(nums[size/2]); // 让序列中点为根节点
        vector<int> leftTree(nums.begin(),nums.begin()+size/2); // 左子树序列
        root->left = sortedArrayToBST(leftTree); // 递归建立左子树
        vector<int> rightTree(nums.begin()+size/2+1,nums.end()); // 右子树序列
        root->right = sortedArrayToBST(rightTree); // 递归建立右子树
        return root;
    }
};
递归优化

在上一个方法中我们新建了左子树和右子树的序列数组,但其实只需要知道左子树和右子树的序列下标即可。因此在这里我们的递归参数需要传递序列下标。

  • 递归参数和返回值:参数是原始的序列数组、要构建子树的序列下标 low、high;返回值是根据序列构建好的二叉树的根节点。

  • 递归结束的条件:当传入的序列数组为空,返回空节点。

  • 递归顺序:前序遍历,每次让序列中点作为根节点,再递归构建左右子树。

class Solution {
public:
    // 左闭右闭
    TreeNode* buildTree(vector<int>& nums, int low, int high){
        if (high < low) return nullptr; // 序列为空,返回空节点
        int mid = (low+high)/2; // 记录中点位置
        TreeNode* root = new TreeNode(nums[mid]); // 让中点为根节点
        root->left = buildTree(nums,low,mid-1); // 建立左子树
        root->right = buildTree(nums,mid+1,high); // 建立右子树
        return root;
    }
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return buildTree(nums,0,nums.size()-1);
    }
};
迭代法

在递归法中我们每次都先根据序列中点建立根节点,再以中点划分左右子树,获取左右子树的区间下标。在迭代法中,我们采取相同思路,用三个队列分别存储新建的根节点、左子树区间、右子树区间。每次都从根节点序列中取出根节点,令根节点的左孩子 = 左子树区间中点,根节点的右孩子 = 右子树区间的中点,再将根节点的左右孩子插入节点队列中,如此循环。

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        int size = nums.size();
        TreeNode* root = new TreeNode(nums[size/2]); // 建立根节点
        
        queue<TreeNode*> nodes; // 记录建立的节点
        nodes.push(root); // 初始为根节点
        
        queue<vector<int>> leftTree; // 记录左子树的下标范围
        leftTree.push({0,size/2-1});
        
        queue<vector<int>> rightTree; // 记录右子树的下标范围
        rightTree.push({size/2+1,size-1});
        
        while (!nodes.empty()){
            TreeNode* father = nodes.front(); nodes.pop(); // 记录父节点
            // 取出左子树区间
            int leftLow = leftTree.front()[0];
            int leftHigh = leftTree.front()[1];
            int leftMid = (leftLow+leftHigh)/2;
            leftTree.pop();
            // 当区间有效时,建立左子树
            if (leftLow <= leftHigh) father->left = new TreeNode(nums[leftMid]);
            // 取出右子树区间
            int rightLow = rightTree.front()[0];
            int rightHigh = rightTree.front()[1];
            int rightMid = (rightLow+rightHigh)/2;
            rightTree.pop();
            // 当区间有效时,建立右子树
            if (rightLow <= rightHigh) father->right = new TreeNode(nums[rightMid]);
            // 继续划分左右子树
            if (leftLow < leftHigh){
                nodes.push(father->left); // 加入左子树根节点
                // 以左子树为根节点划分左右子树
                leftTree.push({leftLow,leftMid-1}); 
                rightTree.push({leftMid+1,leftHigh});
            }
            if (rightLow < rightHigh){
                nodes.push(father->right); // 加入右子树根节点
                // 以右子树为根节点划分左右子树
                leftTree.push({rightLow,rightMid-1});
                rightTree.push({rightMid+1,rightHigh});
            }
        }
        return root;
    }
};

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

题干

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

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

  • 节点的左子树仅包含键 小于 节点键的节点。

  • 节点的右子树仅包含键 大于 节点键的节点。

  • 左右子树也必须是二叉搜索树。

链接:. - 力扣(LeetCode)

思路和代码

由于是二叉搜索树,则 大于等于原节点的值 肯定都在该节点自身及其右子树中。累加的时候可以根据 “右中左” 的顺序遍历二叉树,二叉树的最右节点肯定是二叉树的最大值,没有比他更大的,该节点作为起点,之后再遍历中间节点、左子树。这样每个节点的新值 = 上一个节点的值 + 自己原来的值。

递归法
  • 递归参数和返回值:参数即传入的根节点,无返回值,在递归过程中一步步修改节点值。

  • 递归结束的条件:当传入的节点为空,返回空。

  • 递归顺序:根据 ”右中左“ 的顺序遍历二叉树,先递归右子树,修改中间节点,再递归左子树。

class Solution {
public:
    TreeNode* pre = nullptr; // 记录 遍历过的上一个节点
    void sum(TreeNode* root){ // 计算累加和
        if (root == nullptr) return;
        sum(root->right); // 先遍历右子树
        if (pre != nullptr){
            root->val += pre->val; // 累加节点值
        }
        pre = root;
        sum(root->left); // 遍历左子树
    }
    TreeNode* convertBST(TreeNode* root) {
        sum(root);
        return root;
    }
};
迭代法

思路和之前的方法相同,只不过把反中序递归改为反中序迭代遍历,属于模板题。

class Solution {
public:
    TreeNode* convertBST(TreeNode* root) {
        TreeNode* cur = root;
        stack<TreeNode*> tmpNode;
        TreeNode* pre = nullptr; // 记录 cur 的上一个节点
        while (cur != nullptr || !tmpNode.empty()){
            if (cur != nullptr){
                tmpNode.push(cur);
                cur = cur->right; // 一直遍历右子树直到找到最右节点
            } else{
                // 找到了最右节点
                cur = tmpNode.top();
                tmpNode.pop();
                if (pre != nullptr){
                    cur->val += pre->val; // 修改节点值
                }
                pre = cur;
                cur = cur->left; // 遍历左子树
            }
        }
        return root;
    }
};

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

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

相关文章

数据结构【顺序结构二叉树:堆】(1)

​​​​​​​ &#x1f31f;个人主页&#xff1a;落叶 目录 ​ &#x1f525;树的概念与结构​​​​​​​ &#x1f525;树的表⽰ &#x1f525;孩⼦兄弟表⽰法&#xff1a; &#x1f525;树形结构实际运⽤场景 &#x1f525;⼆叉树 &#x1f525;概念与结构 &…

day4JS-数组

1. 什么是数组 数组是值的有序集合。每个值叫做一个元素。每个元素在数组中有一个位置, 以数字表示,称为索引 (有时也称为下标)。数组的元素可以是任何类型。数组索引从 0 开始,数组最大能容纳 4294967295 个元素。 2. 数组的声明与使用 2.1 使用字面量的方式声明数组 语法…

Minio web控制台实现授权管理

启动minio ./minio server /data01/aidacp/apps/minio/data --config-dir /data01/aidacp/apps/minio/conf --address 127.0.0.1:19090 --console-address 127.0.0.1:19091 &WARNING: Detected Linux kernel version older than 4.0.0 release, there are some known pote…

建设项目跟踪与展示系统

这是在翻旧文件时翻到的16年写的一个项目 建设项目跟踪与展示系统 建设方案 一、系统建设目的及意义 建设工程项目进度控制的最终目的是确保建设项目按预定的时间完成。能否在预定的时间内交付使用&#xff0c;直接影响到投资效益。为解决施工组织过程中存在问题&#xff0c;…

PyTorch深度学习实战(25)—— 使用向量化思想解决实际问题

本文将实际应用向量化思想解决深度学习中的几个经典问题,读者可以在这些示例中进一步领悟向量化思想和高级索引思想。 1. Box_IoU Box_IoU是目标检测任务中最基本的评价指标。简单来说,Box_IoU就是模型预测的检测结果框(predicted bbox)与原始标记框(ground truth)之间的…

企业级Nginx源码安装及其实战讲解

一&#xff1a;web服务基础介绍 1.1Web服务介绍 Apache 经典的 Web 服务端 Apache起初由美国的伊利诺伊大学香槟分校的国家超级计算机应用中心开发 目前经历了两大版本分别是1.X和2.X 其可以通过编译安装实现特定的功能 Apache prefork 模型 预派生模式&#xff0c;有一个…

[C++进阶]map和set

一、关联式容器 STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_list(C11)等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面存储的是元素本身。 那什么是关联式容器&#xff1f;它与序列式容器…

2.复杂度分析

2.1 算法效率评估 在算法设计中&#xff0c;我们先后追求以下两个层面的目标。 找到问题解法&#xff1a;算法需要在规定的输入范围内可靠地求得问题的正确解。寻求最优解法&#xff1a;同一个问题可能存在多种解法&#xff0c;我们希望找到尽可能高效的算法。 也就是说&a…

JavaScript_7_练习:随机抽奖案例

效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>练习&#xff1a;随机抽奖案例</tit…

做谷歌seo如何选择好的服务器?

做谷歌seo如何选择好的服务器&#xff0c;如果你选择自托管平台&#xff0c;那么服务器的选择就非常关键了&#xff0c;服务器的好与坏影响着你的网站的表现&#xff0c;所以选择服务器要慎重。以下是一些建议&#xff0c;帮你做出明智的选择&#xff1a; 安全性&#xff1a;安…

Python Web框架 Django学习记录:1 项目安装,启动

Windows上学习Django # 创建一个虚拟环境 python -m venv tutorial-env# 激活虚拟环境 tutorial-env\Scripts\activate# 安装Django py -m pip install Django# 查看Django版本 py -m django --version# 使用脚手架创建一个项目 django-admin startproject mysite# 启动项目 cd…

linux出现sql密码被忘记的解决方法

目录 前言正文 前言 此处放置在运维篇章&#xff0c;对应sql的修改密码&#xff0c;推荐阅读&#xff1a;修改sql密码&#xff08;涵盖多个版本&#xff09; 如果补充Sql的基本知识&#xff0c;推荐阅读&#xff1a;Mysql底层原理详细剖析常见面试题&#xff08;全&#xff0…

git本地仓库同步到远程仓库

整个过程分为如下几步&#xff1a; 1、本地仓库的创建 2、远程仓库的创建 3、远程仓库添加key 4、同步本地仓库到远程仓库 1、本地仓库的创建&#xff1a; 使用如下代码创建本地仓库&#xff1a; echo "# test" >> README.md git init git add README.md …

shell脚本的编写规范和变量类型

1.shell的作用 shell是Linux系统中后台运行的一种特殊程序也可以理解 成一种特殊的软件&#xff0c;提供了用户与内核进行 交互操作的 一种接口。(简单的说就是shell把人类的高级语言转换成二进制数据&#xff0c;让机器明白你的指令) 过程&#xff1a;用户发出指令&#xff0c…

图像数据处理19

四、形态学图像处理 4.6 灰度图像的形态学处理 4.6.1灰度图像的腐蚀操作 灰度图像的腐蚀处理会让图像整体变暗&#xff0c;增强较暗的细节&#xff0c;抑制较亮的细节。其有助于分割图像、平滑图像边缘。 import cv2 import numpy as np# 读取图像 image cv2.imread(fu.jp…

魔珐科技出席WWEC教育者大会,给出AI时代教培行业精细化运营赋能方案

AI与教育的结合&#xff0c;已经成为教育行业发展的关键增长点。头部机构纷纷寻求AI技术与产品融合&#xff0c;以增强市场竞争力&#xff0c;希望在这场技术引发的行业洗牌中保持领先。 喜忧之中&#xff0c;展望未来&#xff0c;教培机构如何继续找准航向&#xff0c;贴近政…

表格解析调研

表格解析调研 TextInTools TextInTools&#xff1a;https://tools.textin.com/table 可以将表格图片解析成可编辑的表格/json&#xff0c;效果不错 白描 地址&#xff1a;https://web.baimiaoapp.com/image-to-excel 可以将表格图片识别成可编辑的表格&#xff0c;可复制、…

OpenCV4特征匹配

目录 一.特征检测的基本概念二.Harris角点检测三.Shi-Tomasi角点检测四.SIFT关键点检测五.SURF特征检测&#xff08;属于opencv_contrib&#xff09;六.ORB特征检测七.特征匹配方法八.FLANN特征匹配 流程梳理 一.特征检测的基本概念 OpenCV特征的场景 1.图像搜索&#xff0c;…

“论软件的可靠性评价”写作框架,软考高级,系统架构设计师

论文真题 软件可靠性评价是软件可靠性活动的重要组成部分&#xff0c;既适用于软件开发过程&#xff0c;也可针对最终软件系统。在软件开发过程中使用软件可靠性评价&#xff0c;可以使用软件可靠性模型&#xff0c;估计软件当前的可靠性&#xff0c;以确认是否可以终止测试并…

数据结构与算法(算法篇)

学数据结构与算法不是仅仅学算法本身&#xff08;经验&#xff09;&#xff0c;而是学习思维&#xff08;解决问题的能力)。 数据结构与算法&#xff08;算法篇&#xff09; 1、算法的性能分析1.1 时间复杂度1.2 空间复杂度1.3 小结 2、高精度2.1 高精度加法2.2 高精度减法2.3…