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. 把二叉搜索树转换为累加树的更多相关文章

  1. 代码随想录算法训练营day23 | leetcode 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树

    LeetCode 669. 修剪二叉搜索树 分析1.0 递归遍历树时删除符合条件(不在区间中)的节点-如何遍历如何删除 如果当前节点大于范围,递归左树,反之右树 当前节点不在范围内,删除它,把它的子树 ...

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

    第108题 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定有序数组: [-10 ...

  3. [LeetCode] 108. 将有序数组转换为二叉搜索树

    题目链接 : https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/ 题目描述: 将一个按照升序排列的 ...

  4. [LeetCode]105. 从前序与中序遍历序列构造二叉树(递归)、108. 将有序数组转换为二叉搜索树(递归、二分)

    题目 05. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 题解 使用HashMap记录当前子树根节点在中序遍历中的位置,方便每次 ...

  5. LeetCode 108. 将有序数组转换为二叉搜索树(Convert Sorted Array to Binary Search Tree) 14

    108. 将有序数组转换为二叉搜索树 108. Convert Sorted Array to Binary Search Tree 题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索 ...

  6. Java实现 LeetCode 108 将有序数组转换为二叉搜索树

    108. 将有序数组转换为二叉搜索树 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: ...

  7. LeetCode【108. 将有序数组转换为二叉搜索树】

    又是二叉树,最开始都忘记了二叉搜索树是什么意思,搜索了一下: 二叉搜索树:左节点都小于右节点,在这里就可以考虑将数组中的中间值作为根节点 平衡二叉树:就是左右节点高度不大于1 树就可以想到递归与迭代, ...

  8. LeetCode 108——将有序数组转化为二叉搜索树

    1. 题目 2. 解答 一棵高度平衡的二叉搜索树意味着根节点的左右子树包含相同数量的节点,也就是根节点为有序数组的中值. 因此,我们将数组的中值作为根节点,然后再递归分别得到左半部分数据转化的左子树和 ...

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

    原题链接 思路: 二叉搜索树的定义: 它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的 ...

  10. leecode第四题(寻找两个有序数组的中位数)

    题解: class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<i ...

随机推荐

  1. Flink程序异常--CommunicationsException: The last packet successfully received from the server was

    一.异常截图 com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully receive ...

  2. Luogu P9055 [集训队互测 2021] 数列重排 题解 [ 紫 ] [ 构造 ] [ 数学 ]

    数列重排:差点就场切的神仙构造,最后一步想假了,导致我模拟赛荣获 25+5+0 的好成绩! 这题部分分很有启发性,跟着一步一步打基本能想到正解的构造,但也有可能想偏部分分的意思,想假策略. 构造 先看 ...

  3. 五分钟搞定!Linux平台上用Ansible自动化部署SQL Server AlwaysOn集群

    五分钟搞定!Linux平台上用Ansible自动化部署SQL Server AlwaysOn集群 前言 以下内容是由红帽官方博客整理而成,使用Ansible在Linux平台上自动化部署SQL Serv ...

  4. 分享一个 Windows 下的透明锁屏工具【开源】

    透明锁屏 担心展示内容时被误操作打断? 害怕离开后忘记锁屏导致隐私泄露? 厌倦了千篇一律的系统锁屏界面? 透明锁屏 了解一下. 功能特点 告别误操作:锁屏状态下,屏幕内容依然可见,视频播放.PPT 演 ...

  5. vue element UI el-table表格添加行点击事件

    <el-table @row-click="openDetails"></el-table> //对应的 methods 中//点击行事件methods: ...

  6. PERT 图表教程

    (翻译自: PERT Chart Tutorial) PERT 图表 是(程序评估和审查技术)的首字母缩写.PERT 图是一种项目管理工具,用于在项目中安排.组织和协调任务.它基本上是一种分析完成给定 ...

  7. 解决2023新版Edge浏览器页面加载不出来问题

    如果你遇到2023新版Edge浏览器页面无法加载的问题,可以尝试以下几种解决方法: 检查网络连接:确保你的网络连接正常,可以尝试打开其他网页或使用其他应用程序进行网络测试. 清除浏览器缓存:打开Edg ...

  8. HDP集群部署

    一.环境准备 centos7 安装和系统环境处理 1)运行初始化脚本 !/bin/bash ------------------------------------- 系统环境初始化脚本 本脚本仅支持 ...

  9. 分享4款.NET开源、免费、实用的商城系统

    前言 今天大姚给大家分享4款.NET开源.免费.实用的商城系统,希望可以帮助到有商城系统开发需求的同学. nopCommerce nopCommerce是一个.NET开源功能丰富.免费.灵活且可定制的 ...

  10. manim边学边做--局部缩放的场景类

    在动画制作中,尤其是数学和科学可视化领域,有时我们需要将观众的注意力集中在场景的某个特定部分. Manim提供了一个强大的工具 ZoomedScene,它允许我们在场景中创建一个独立的缩放视图,从而实 ...