【算法与数据结构】450、LeetCode删除二叉搜索树中的节点

news2024/11/28 22:34:34

文章目录

  • 一、题目
  • 二、解法
  • 三、完整代码

所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。

一、题目

在这里插入图片描述
在这里插入图片描述

二、解法

  思路分析:本题首先要分析删除节点的五种情况:

  • 1、没有找到节点
  • 2、找到节点
    • 左右子树为空
    • 左子树为空,右子树不为空
    • 右子树为空,左子树不为空
    • 左右子树均不为空
        程序当中我们选择递归法解题,终止条件中返回一个节点,令上一层递归接住。没有找到节点说明树中没有对应节点的键值,应该是找到空节点的情况。左右子树均为空,说明是叶子节点,返回空节点,并释放空间,上一层中该节点就被置为空节点。左子树不为空,右子树为空,返回左子树即可,反之亦然。左右子树均为不为空的情况比较复杂,因为上一层只接收一个删除后的根节点值,为了使删除后的二叉树仍为二叉搜索树,需要将左右子树合并成一个新的二叉搜索树。那么我们只需将目标节点左子树补位到右子树最底层最左边的节点上,右子树最底层最左边的节点实际上是右子树中键值最小的节点(这个大家可以自己画一个二叉搜索树看看),左子树的值都比这个节点的键值还小,因此需要补位到这个节点的左孩子位置上,伪代码如下,程序当中使用一个while循环寻找右孩子最底层最左边的节点:
	右孩子最底层最左边的节点->left = root->left;
	auto retNode = root->right;
	delete root;
	return retNode;

  程序如下

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == NULL) return root;  // 没找到节点
        if (root->val == key) {         // 找到节点
            if (root->right == NULL && root->left == NULL) {    // 左右孩子均为空,返回空节点
                delete root;
                return NULL; 
            }
            else if (root->left == NULL) {  // 左孩子为空,右孩子不为空,返回右孩子
                auto retNode = root->right;
                delete root;
                return retNode; 
            }
            else if (root->right == NULL) { // 右孩子为空,左孩子不为空,返回左孩子
                auto retNode = root->left;
                delete root;
                return retNode;  
            }
            else {  // 左右孩子均不为空,左孩子补位到右孩子最底层最左边的节点上  
                TreeNode* cur = root->right;
                while (cur->left != NULL) {
                    cur = cur->left;
                }
                cur->left = root->left;
                auto retNode = root->right;
                delete root;
                return retNode;
            }            
        }
        if (root->val > key) root->left = deleteNode(root->left, key);
        if (root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
};

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n),最差情况下,寻找和删除个需要遍历一次树。
  • 空间复杂度: O ( n ) O(n) O(n),递归的深度最深为 O ( n ) O(n) O(n)

三、完整代码

# include <iostream>
# include <vector>
# include <string>
# include <queue>
using namespace std;

// 树节点定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == NULL) return root;  // 没找到节点
        if (root->val == key) {         // 找到节点
            if (root->right == NULL && root->left == NULL) {    // 左右孩子均为空,返回空节点
                delete root;
                return NULL; 
            }
            else if (root->left == NULL) {  // 左孩子为空,右孩子不为空,返回右孩子
                auto retNode = root->right;
                delete root;
                return retNode; 
            }
            else if (root->right == NULL) { // 右孩子为空,左孩子不为空,返回左孩子
                auto retNode = root->left;
                delete root;
                return retNode;  
            }
            else {  // 左右孩子均不为空,左孩子补位到右孩子最底层最左边的节点上  
                TreeNode* cur = root->right;
                while (cur->left != NULL) {
                    cur = cur->left;
                }
                cur->left = root->left;
                auto retNode = root->right;
                delete root;
                return retNode;
            }            
        }
        if (root->val > key) root->left = deleteNode(root->left, key);
        if (root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
};

// 前序遍历迭代法创建二叉树,每次迭代将容器首元素弹出(弹出代码还可以再优化)
void Tree_Generator(vector<string>& t, TreeNode*& node) {
    if (!t.size() || t[0] == "NULL") return;    // 退出条件
    else {
        node = new TreeNode(stoi(t[0].c_str()));    // 中
        if (t.size()) {
            t.assign(t.begin() + 1, t.end());
            Tree_Generator(t, node->left);              // 左
        }
        if (t.size()) {
            t.assign(t.begin() + 1, t.end());
            Tree_Generator(t, node->right);             // 右
        }
    }
}

template<typename T>
void my_print(T& v, const string msg)
{
    cout << msg << endl;
    for (class T::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << ' ';
    }
    cout << endl;
}

template<class T1, class T2>
void my_print2(T1& v, const string str) {
    cout << str << endl;
    for (class T1::iterator vit = v.begin(); vit < v.end(); ++vit) {
        for (class T2::iterator it = (*vit).begin(); it < (*vit).end(); ++it) {
            cout << *it << ' ';
        }
        cout << endl;
    }
}

// 层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {
    queue<TreeNode*> que;
    if (root != NULL) que.push(root);
    vector<vector<int>> result;
    while (!que.empty()) {
        int size = que.size();  // size必须固定, que.size()是不断变化的
        vector<int> vec;
        for (int i = 0; i < size; ++i) {
            TreeNode* node = que.front();
            que.pop();
            vec.push_back(node->val);
            if (node->left) que.push(node->left);
            if (node->right) que.push(node->right);
        }
        result.push_back(vec);
    }
    return result;
}

int main()
{
    // 构建二叉树
    vector<string> t = { "5", "3", "2", "NULL", "NULL", "4", "NULL", "NULL", "6", "NULL", "7", "NULL", "NULL" };   // 前序遍历
    my_print(t, "目标树");
    TreeNode* root = new TreeNode();
    Tree_Generator(t, root);
    vector<vector<int>> tree = levelOrder(root);
    my_print2<vector<vector<int>>, vector<int>>(tree, "目标树:");

    // 删除目标值
    int key = 5;
    Solution s;
    TreeNode* result = s.deleteNode(root, key);
    vector<vector<int>> tree1 = levelOrder(result);
    my_print2<vector<vector<int>>, vector<int>>(tree1, "目标树:");

    system("pause");
    return 0;
}

end

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

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

相关文章

什么是线上商城?线上商城小程序怎么搭建?

线上商城是一种基于互联网的销售模式。它通过建立线上商店&#xff0c;展示、销售各类商品或服务&#xff0c;方便消费者在线上完成购买和支付。线上商城的出现在很大程度上改变了人们的购物习惯&#xff0c;为商家和消费者提供了更加便捷、高效的交易方式。 线上商城可以是网站…

SAP ALV 报表增删改查 及 下载模板导入文件

选择屏幕设置&#xff1a; 选择屏幕********************************************************************** * SELECTION-SCREEN ********************************************************************** SELECTION-SCREEN BEGIN OF BLOCK BLK1 WITH FRAME TITLE TEXT-001…

R语言ggpubr包优雅绘制带统计数据的箱线图

ggpubr包是个很经典的R包&#xff0c;能绘制专业的论文绘图&#xff0c;它是对ggplot2进行了加强&#xff0c;R包的说明也是介绍用于创建和自定义基于“ggplot2”的出版物绘图&#xff0c;就是个为SCI而生的R包呀&#xff0c;今天咱们使用ggpubr绘制专业的论文需要的带统计数据…

一文图解|内存页面迁移技术

1. 概述 页面迁移&#xff08;page migrate&#xff09;最早是为 NUMA 系统提供一种将进程页面迁移到指定内存节点的能力用来提升访问性能。后来在内核中广泛被使用&#xff0c;如内存规整、CMA、内存hotplug等。 页面迁移对上层应用业务来说是不可感知的&#xff0c;因为其迁…

【无标题】同创永益王澍│新环境下数字韧性建设探讨

2023年9月7日&#xff0c;由同创永益主办的2023数字韧性保险峰会在上海成功举办。ITSS DCMG组长肖建一等数十位保险行业专家、企业代表出席本次会议&#xff0c;同创永益与多方共同探讨保险行业数字化发展与数字韧性体系建设&#xff0c;共话行业数智化未来。 会上&#xff0c…

贵阳RapidSSL的ssl证书适合个人网站吗

现在很多开发者不论是为了记录还是宣传&#xff0c;很多人都会创建一个属于自己的网站&#xff0c;而有了自己的网站&#xff0c;为了保护网站信息安全以及防止网站数据被篡改与劫持&#xff0c;就需要为网站安装SSL证书。那么RapidSSL的SSL证书个人开发者可以使用吗&#xff1…

Windows Server 2008安装.NET Framework 3.5

安装.NET Framework 3.5一、打开服务器管理器 在开始菜单中搜索“服务器管理器” 二、添加.NET Framework 3.5.1功能 &#xff08;一&#xff09;功能-》添加功能 &#xff08;二&#xff09;选择功能“.NET Framework 3.51” 1.点击“NET Framework 3.5.1”勾选框 2.点击“添…

python教程:内置函数和语法糖触发魔法方法

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 下面总结python内置函数对应的魔法方法 魔法方法 数学计算 abs(args):返回绝对值&#xff0c;调用__abs__; round(args):返回四舍五入的值&#xff0c;调用__roun…

GPIO基础知识的概括

GPIO 是通用输入/输出端口的简称&#xff0c;本文以STM32为例进行说明&#xff0c;其他的单片机功能上都是大同小异&#xff0c;学会STM32的GPIO&#xff0c;我们可以触类旁通。 GPIO 的引脚与外部硬件设备连接&#xff0c;可实现与外部通讯、控制外部硬件或者采集外部硬件数据…

CMS之织梦导航二级下拉菜单

操作步骤 1、首先&#xff1a; 将下面这段代码贴到templets\default\footer.htm文件里&#xff08;只要在此文件里就行&#xff0c;位置无所谓啦&#xff01;自己看着办&#xff01;&#xff09; <!-- //二级子类下拉菜单&#xff0c;考虑SEO原因放置于底部 --><scr…

最大限度节省采购成本的七种方法

当前经济环境下&#xff0c;降低成本比以往任何时候都更受到企业的重视。降低成本通常是指在采购过程中节省的成本&#xff0c;但其实远不止于此。它还包括通过重新谈判合同条款和条件、改进管理和运营流程&#xff0c;以及数据和技术的智能使用而节省的成本。 节省采购成本的…

提升技术招聘有效性| 杜绝候选人刷题应试

企业在技术人员招聘中&#xff0c;时常出现候选人“笔试考高分&#xff0c;工作写Bug&#xff0c;绩效来垫底”的尴尬窘境&#xff0c;让企业倍感煎熬。不仅浪费时间精力、也增大招人的成本投入。 如何招到真正合适的技术人选&#xff0c;成为摆在企业心头的难题。 合适的技术…

Vue中的生命周期钩子

生命周期钩子 :::warning 注意 所有生命周期钩子的 this 上下文将自动绑定至实例中&#xff0c;因此你可以利用 this 访问 props、data、computed 和 methods 等选项内的数据/函数。这意味着你不应该使用箭头函数来定义一个生命周期方法&#xff0c;因为箭头函数中没有 this&a…

基于Kintex UltraScale系列FPGA KU060/KU115高性能PCIe数据预处理载板(5GByte/s带宽)

PCIE702是一款基于PCIE总线架构的高性能数据预处理FMC载板&#xff0c;板卡具有1个FMC&#xff08;HPC&#xff09;接口&#xff0c;1路PCIe x8主机接口、1个RJ45千兆以太网口、2个QSFP 40G光纤接口。板卡采用Xilinx的高性能Kintex UltraScale系列FPGA作为实时处理器&#xff0…

vuex实现简易购物车加购效果

目录 一、加购效果动图二、前提条件三、开始操作四、解决vuex刷新数据丢失问题五、最终效果 一、加购效果动图 二、前提条件 创建了vue项目&#xff0c;安装了vuex 三、开始操作 目录结构如下&#xff1a; main.js文件中引入store: import Vue from vue import App from ./…

星戈瑞Cyanine7-COOH在生物学和医学中的应用 CY7-COOH

Cyanine7-COOH作为一种近红外荧光染料&#xff0c;在生物学和医学领域应用。以下是一些Cyanine7-COOH在这些领域中可能的应用&#xff1a; 生物荧光成像&#xff1a; Cyanine7-COOH可以用于细胞和组织的荧光成像&#xff0c;特别是在近红外范围内。这个波长范围的荧光信号穿透…

分布式链路追踪系统zipkin【杭州多测师_王sir】

一、部署zipkin环境的方式 》1.docker 2、java -jar 3、运行源码 二、分别可以在Linux系统和Windows系统里面运行zipkin 三、在地址栏输入&#xff1a;http://127.0.0.1:9411 四、zipkin的流程图 由上图可以看出&#xff0c;应用的代码(User Code)发起 Http Get 请求(请…

Unity丨移动相机朝向目标并确定目标在摄像机可视范围内丨摄像机注释模型丨摄像机移动丨不同尺寸模型优化丨

文章目录 问题描述功能展示技术细节小结 问题描述 本文提供的功能是摄像机朝向目标移动&#xff0c;并确定整个目标出现在摄像机视角内&#xff0c;针对不同尺寸的模型优化。 功能展示 提示&#xff1a;这里可以添加技术名词解释 技术细节 直接上代码 using UnityEngine;…

阿里云产品试用系列-函数计算 FC

函数计算&#xff08;Function Compute&#xff09;是一个事件驱动的全托管 Serverless 计算服务&#xff0c;您无需管理服务器等基础设施&#xff0c;只需编写代码并上传&#xff0c;函数计算会为您准备好计算资源&#xff0c;并以弹性、可靠的方式运行您的代码。 如上所示&am…

Selenium 4.11 正式发布--再也不用手动更新chrome driver 了

Selenium 4.11.0 正式发布了&#xff0c;先来看一下主要特性。 Chrome DevTools支持的版本现在是&#xff1a;v113、v114和v115&#xff08;Firefox仍然对所有版本使用v85&#xff09; 通过Selenium Manager支持Chrome For Testing&#xff08;CfT&#xff09; Selenium Manag…