代码随想录第二十一天 | Leecode 669. 修剪二叉搜索树、108. 将有序数组转换为二叉搜索树、538. 把二叉搜索树转换为累加树
Leecode 669. 修剪二叉搜索树
题目描述
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
- 示例 1:
输入:root = [1,0,2],low = 1,high = 2
输出:[1,null,2]
- 示例 2:
输入:root = [3,0,4,null,2,null,null,1],low = 1,high = 3
输出:[3,2,null,1]
递归法解题思路与代码
本题要求修剪二叉搜索树中大于和小于目标区间的节点,最基本的是需要知道二叉搜索树的性质,其向下投影(中序遍历)即为有序序列。其次的关键在于要对每个节点的可能情形都进行分类讨论,此时需要注意不能漏掉某一情形,同时要清晰对于每种情况都要如何操作。首先我们先讨论如何来进行分情况讨论。
每个节点的值可能取到的大小0 <= low <= high <= 10^4,同时我们需要保留其中取值在[low, high]闭区间内的值,那么就相当于把数轴划分为三段,分别为:
[0,low),在代码中可以具体表示为Node->val < low;[low, high],即Node->val >= low && Node->val <= high;(high, 10^4],即Node->val > high。
根据上面的分类情况,就能考虑到每一个节点的所有情况,接下来我们再说明对于其中每一种情况需要如何处理:
- 当
Node->val < low时,当前节点及其左子树都不满足条件,但是右子树是否满足还未知。因此可以考虑使用右子节点来替代当前节点,继续递归处理当前节点 - 当
Node->val >= low && Node->val <= high时,当前节点满足条件,此时递归处理左右子树 - 当
Node->val > high时,类似第一种情况,右子树和当前节点都不满足,用左子节点来替代当前节点。并再将当前节点传入递归
根据上面算法思想,即可实现如下代码:
class Solution {
public:
void cutHelper(TreeNode*& curNode, int low, int high){
if(!curNode) return; // 如果当前节点已经为空,则直接返回
if(curNode->val < low) { // 如果当前节点已经小于下界,则用其右子节点来替代当前节点
if(curNode->val < low)curNode = curNode->right; // 用右子节点来替代当前节点
if(curNode)cutHelper(curNode, low, high); // 继续将当前节点传入递归修剪(因当前节点已经被替换,所以继续传当前节点)
}
else if(curNode->val >= low && curNode->val <= high){ // 如果当前节点满足条件,则需要分别对左右子树进行修剪
cutHelper(curNode->left, low, high); // 递归修剪左子树
cutHelper(curNode->right, low, high); // 递归修剪右子树
}
else if(curNode->val > high){ // 如果当前节点的值大于上界,则将
if(curNode->val > high) curNode = curNode->left;
if(curNode)cutHelper(curNode, low, high);
}
}
TreeNode* trimBST(TreeNode* root, int low, int high) {
cutHelper(root, low, high);
return root;
}
};
上面代码的最坏时间复杂度为\(O(n)\),即每个节点都需要进行一次判断,判断其是否落在区间内。但实际上每次判断后根据二叉搜索树的性质,可以知道当前节点左右子树是否有可能满足,从而省略一部分判断用时从而减少时间复杂度。
Leecode 108. 将有序数组转换为二叉搜索树
题目描述
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 平衡 二叉搜索树。
- 示例 1:
输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9]也将被视为正确答案:
- 示例 2:
输入:nums = [1,3]
输出:[3,1]
解释:[1,null,3]和[3,1]都是高度平衡二叉搜索树。
解题思路与代码展示
本题是建立二叉树的题目,此前已经做过几道类似的题目。关键在于划分数组,以用于建立当前节点的值作为分割点,将数组分为两半,并后续分别用于递归构造左右子树。本题特别的点在于是需要建立平衡的二叉搜索树,为了平衡性,我们可以考虑每次使用当前数组的中点作为当前节点的值并对数组进行分割,这样就可以保证左右子树中的节点个数只相差1,从而确保了平衡性。
class Solution {
public:
void buildHelper(TreeNode*& curRoot, vector<int> curVec){
if(curVec.empty()) return; // 如果当前向量已经为空,则直接返回
int cutPoint = curVec.size()/2 ; // 使用有序数组的中点作为分割点
curRoot = new TreeNode(curVec[cutPoint]); // 使用中点值来建立当前节点
vector<int> leftVec(curVec.begin(), curVec.begin()+cutPoint); // 建立左子数组
buildHelper(curRoot->left, leftVec); // 递归建立左子树
vector<int> rightVec(curVec.begin()+cutPoint+1,curVec.end()); // 建立右子数组
buildHelper(curRoot->right, rightVec); // 递归建立右子树
return;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
TreeNode* root = nullptr; // 讨论空节点的情况
buildHelper(root, nums); // 调用递归函数进行建树
return root;
}
};
Leecode 538. 把二叉搜索树转换为累加树
题目描述
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
- 示例 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]
递归法 解题思路与代码
本题使用递归来进行深度优先算法。因为要将每个节点转换为本身与右边所有节点的和,所以可以知道一开始必须走到最左边的那个节点并记录求和值。只要能够想通深度优先就是中序遍历,那么本题就没有什么难度了。直接在中序遍历递归的基础上,将其更改为记录求和并更新当前节点的操作即可。故有下面代码:
class Solution {
public:
void convertHelper(TreeNode* curNode, int& sum){ // 使用中序遍历来进行递归
if(!curNode) return; // 如果当前节点为空则返回
convertHelper(curNode->right, sum); // 向右递归
sum += curNode->val; // 将当前节点值加到sum上
curNode->val = sum; // 在令当前节点值等于sum
convertHelper(curNode->left, sum); // 向左递归
}
TreeNode* convertBST(TreeNode* root) {
int sum = 0;
convertHelper(root, sum);
return root;
}
};
时间复杂度为\(O(n)\),即每个节点遍历一次。
今日总结
实际上是昨日总结...因为本来该4.15发的打卡到了4.16才发,原因是昨天去看了DragonForce北京演出。
发现二叉树部分的题目暂时算是刷完了,总的来说感觉大部分题目用递归来解决都并不算难,关键在于说要去往前、中、后序遍历的方向去套。以及递归中需要分情况讨论的地方要把所有可能性都考虑到,那么就基本都能做出来。
同时还有一个非常重要的点在于,在层序遍历中使用队列来解决问题的范式模板,注意当需要分层解决问题的时候,需要固定每一次循环开始时的队列长度,用于表示当前层的节点个数。
二叉树最难的地方感觉就在于,使用迭代来求解的时候,对于前序遍历和中序遍历的迭代法需要充分掌握。还有就是当遇到需要自下而上的算法的时候,需要使用回溯的方式。对于回溯算法,如果使用递归来实现,使用值传递可以免去一次pop出栈操作,但是值传递可能会导致每一次递归都复制一个栈,当数据量较大时会占用很大的空间。如果使用引用的方式进行回溯,则每次递归之后要手动使用pop进行回溯。
大致上总结了一下最近学到的东西,以及记录当前力扣进度:
目前力扣已经79题了,100题尽在眼前,继续加油
代码随想录第二十一天 | Leecode 669. 修剪二叉搜索树、108. 将有序数组转换为二叉搜索树、538. 把二叉搜索树转换为累加树的更多相关文章
- 代码随想录算法训练营day23 | leetcode 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树
LeetCode 669. 修剪二叉搜索树 分析1.0 递归遍历树时删除符合条件(不在区间中)的节点-如何遍历如何删除 如果当前节点大于范围,递归左树,反之右树 当前节点不在范围内,删除它,把它的子树 ...
- LeetCode 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树
第108题 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定有序数组: [-10 ...
- [LeetCode] 108. 将有序数组转换为二叉搜索树
题目链接 : https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/ 题目描述: 将一个按照升序排列的 ...
- [LeetCode]105. 从前序与中序遍历序列构造二叉树(递归)、108. 将有序数组转换为二叉搜索树(递归、二分)
题目 05. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 题解 使用HashMap记录当前子树根节点在中序遍历中的位置,方便每次 ...
- LeetCode 108. 将有序数组转换为二叉搜索树(Convert Sorted Array to Binary Search Tree) 14
108. 将有序数组转换为二叉搜索树 108. Convert Sorted Array to Binary Search Tree 题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索 ...
- Java实现 LeetCode 108 将有序数组转换为二叉搜索树
108. 将有序数组转换为二叉搜索树 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: ...
- LeetCode【108. 将有序数组转换为二叉搜索树】
又是二叉树,最开始都忘记了二叉搜索树是什么意思,搜索了一下: 二叉搜索树:左节点都小于右节点,在这里就可以考虑将数组中的中间值作为根节点 平衡二叉树:就是左右节点高度不大于1 树就可以想到递归与迭代, ...
- LeetCode 108——将有序数组转化为二叉搜索树
1. 题目 2. 解答 一棵高度平衡的二叉搜索树意味着根节点的左右子树包含相同数量的节点,也就是根节点为有序数组的中值. 因此,我们将数组的中值作为根节点,然后再递归分别得到左半部分数据转化的左子树和 ...
- LeetCode 之 108. 将有序数组转换为二叉搜索树
原题链接 思路: 二叉搜索树的定义: 它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的 ...
- leecode第四题(寻找两个有序数组的中位数)
题解: class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<i ...
随机推荐
- python接入百度智能云API实现ai对话
python接入百度智能云API实现ai对话 千帆大模型平台-百度智能云千帆 代码段: import requests import json # 获取访问令牌的函数 def get_access_t ...
- 解密prompt系列49. 回顾R1之前的思维链发展路线
在所有人都在谈论R1的今天,作为算法也是有些千头万绪无从抓起.所以这一章先复盘,我先按照自己的思路来梳理下R1之前整个模型思维链的发展过程.下一章再展望主要去看RL在Agent上的一些尝试,毕竟Age ...
- QT5笔记:24. 自定义对话框以及模态 调用
创建窗口时 窗口对象为QDialog 调用方法为exec(); int res = setSizeDialog->exec();//模态窗口 (不必要)exec可以获取到调用的是对话框的 QDi ...
- [tldr] fish shell添加环境变量到配置文件
fish shell配置文件的编写格式和位置都和bash不同 文件位置 位于~/.config/fish/config.fish 设置PATH fish shell不会去读取~/.bashrc文件中的 ...
- 解决本地代理问题 git 或者 curl Failed to connect to 127.0.0.1 port 1087 after 8 ms: Connection refused
问题出现原因 git配置了代理 本地配置了代理 执行这个命令可以看到自己的代理设置: env | grep -I proxy 临时更改代理 在当前终端执行以下命令,就可以临时将代理取消掉 export ...
- go ERROR invalid character '<' looking for beginning of value
报错 go ERROR invalid character '<' looking for beginning of value 请检查服务器响应数据是否正确,能够正确被 json 解析 一般碰 ...
- NumPy学习5
今天学习了11, NumPy数组元素增删改查NumPy 数组元素的增删改查操作,主要有以下方法:数组元素操作方法函数名称 描述说明resize 返回指定形状的新数组.append 将元素值添加到数组的 ...
- MinIO Linux 数据迁移
目录 安装 下载 安装Minio客户端 备份数据 数据还原 数据迁移 设置别名 迁移 从A服务器,迁移致B服务器,前提,需要两边的 Bucket 相同,如果B服务器没有A服务器里的 Bucket 需要 ...
- 漏洞编号CVE-2022-27191 漏洞公告 ALINUX3-SA-2024:0050: container-tools:rhel8 安全和BUG修复更新
基于Debian的系统(如Ubuntu),使用apt sudo apt-get update sudo apt-get install --only-upgrade container-selinux ...
- SQL Server 中的异常处理
为什么我们需要 SQL Server 中的异常处理? 让我们通过一个示例来了解 SQL Server 中异常处理的必要性.因此,创建一个 SQL Server 存储过程,通过执行以下查询来除以两个数字 ...






