【算法与数据结构】669、LeetCode修剪二叉搜索树

news2024/9/21 11:14:46

文章目录

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

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

一、题目

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

二、解法

  思路分析:450、LeetCode删除二叉搜索树中的节点两道题的思路几乎是一样的,只不过终止条件和单层递归逻辑的顺序需要调换,因为本题需要删除的可能不止一个节点,需要先递归到最深处(只要节点非空),然后进行判断,否则在根节点为[low, high]区间外时它把根节点一删除就没有后续操作了,但此时树里面可能还有区间外的节点,造成漏删。删除类型一共有5种,450题已经分析过了。
  程序如下

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if (root == NULL) return root;  // 没找到节点
        root->left = trimBST(root->left, low, high);
        root->right = trimBST(root->right, low, high);

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

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n),需要遍历每一个元素。
  • 空间复杂度: O ( n ) O(n) O(n),最坏情况下,递归深度为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* trimBST(TreeNode* root, int low, int high) {
        if (root == NULL) return root;  // 没找到节点
        root->left = trimBST(root->left, low, high);
        root->right = trimBST(root->right, low, high);

        if (root->val < low || root->val > high) {         // 找到节点
            if (root->right == NULL && root->left == NULL) {    // 左右孩子均为空,返回空节点
                return NULL;
            }
            else if (root->left == NULL) {  // 左孩子为空,右孩子不为空,返回右孩子
                auto retNode = root->right;
                return retNode;
            }
            else if (root->right == NULL) { // 右孩子为空,左孩子不为空,返回左孩子
                auto retNode = root->left;
                return retNode;
            }
            else {  // 左右孩子均不为空,左孩子补位到右孩子最底层最左边的节点上  
                TreeNode* cur = root->right;
                while (cur->left != NULL) {
                    cur = cur->left;
                }
                cur->left = root->left;
                auto retNode = root->right;
                return retNode;
            }
        }
        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 = { "3", "0", "NULL", "2", "1", "NULL", "NULL", "NULL", "4", "NULL", "NULL" };   // 前序遍历
    //vector<string> t = { "1", "NULL", "2", "NULL", "NULL"};   // 前序遍历
    vector<string> t = { "2", "1", "NULL", "NULL", "3", "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 low = 3;
    int high = 4;
    Solution s;
    TreeNode* result = s.trimBST(root, low, high);
    vector<vector<int>> tree1 = levelOrder(result);
    my_print2<vector<vector<int>>, vector<int>>(tree1, "结果树:");

    system("pause");
    return 0;
}

end

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

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

相关文章

#循循渐进学51单片机#定时器与数码管#not.4

1、熟练掌握单片机定时器的原理和应用方法。 1&#xff09;时钟周期&#xff1a;单片机时序中的最小单位&#xff0c;具体计算的方法就是时钟源分之一。 2&#xff09;机器周期&#xff1a;我们的单片机完成一个操作的最短时间。 3)定时器&#xff1a;打开定时器“储存寄存器…

前端-layui动态渲染表格行列与复杂表头合并

说在前面&#xff1a; 最近一直在用layui处理表格 写的有些代码感觉还挺有用的&#xff0c;顺便记录下来方便以后查看使用&#xff1b; HTML处代码 拿到id 渲染位置表格 <div class"layui-table-body salaryTable"><table class"layui-table" i…

Faunadb入门

Faunadb和google spanner都属于云分布式数据库天然支持分片(无需做分表分库操作&#xff0c;一库搞定&#xff0c;当然价格另说)&#xff0c;国内的也有比如TiDB Oceanbase等 本文使用java语言&#xff0c;其他语言可以跳过&#xff1b;有想直接使用的可以参考(无法访问外网&…

uniapp开发h5,解决项目启动时,Network: unavailable问题

网上搜了很多&#xff0c;发现都说是要禁用掉电脑多余的网卡&#xff0c;这方法我试了没有好&#xff0c;不晓得为啥子&#xff0c;之后在网上看&#xff0c;uniapp的devServer vue2的话对标的就是webpack4的devserver&#xff08;除了复杂的函数配置项&#xff09;&#xff0c…

牛客: BM5 合并k个已排序的链表

牛客: BM5 合并k个已排序的链表 文章目录 牛客: BM5 合并k个已排序的链表题目描述题解思路题解代码 题目描述 题解思路 合并链表数组中的前两条链表,直到链表数组的长度为一, 返回这个唯一的链表 题解代码 package main/** type ListNode struct{* Val int* Next *ListN…

一个十分好用且美观的vue3后台管理系统框架

给大家推荐一个十分好用且美观的vue3后台管理系统框架 码云地址 项目完全开源&#xff0c;另外还给想学习框架搭建的同学&#xff0c;准备了学习视频&#xff0c;价格美丽&#xff0c;保证物美价廉。 试看视频 项目技术栈 Vue3Vite4Typescript5piniaelement plusUnocsspnp…

Git的基本操作:分支管理

8 分支管理 这里主要体现的git的功能的分离&#xff0c;这才是真正的git吧。每一个分支都是一个单独的可以分离的工作单位。每个用户可以建立不同的分支进行工作&#xff0c;最终提交到同一个开发分支上。一个用户可以建立不同的分支实现不同的功能&#xff0c;最终提交到同一…

CPU的三级缓存

CPU缓存&#xff08;Cache Memory&#xff09;是位于CPU与内存之间的临时存储器&#xff0c;它的容量比内存小的多但是交换速度却比内存要快得多。高速缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾&#xff0c;因为CPU运算速度要比内存读写速度快很多&#…

Python语言学习实战-内置函数filter()的使用(附源码和实现效果)

实现功能 filter()函数是Python的内置函数之一&#xff0c;用于过滤序列中的元素。它接受两个参数&#xff1a;一个是函数&#xff0c;用于判断每个元素是否符合条件&#xff1b;另一个是可迭代对象&#xff0c;包含要过滤的元素。filter()函数返回一个迭代器&#xff0c;其中包…

Spring MVC里的DispatchServlet(结合Spring官网翻译)

Spring MVC里的DispatchServlet 前言1.Spring Web MVC1.1 DispatcherServlet&#xff08;中央调度器&#xff09;1.1.1 Context Hierarchy&#xff08;上下文层次结构&#xff09;1.1.2 Special Bean Types&#xff08;特定的bean类型&#xff09;1.1.3 Web MVC Config1.1.4 Se…

c++基础第三章:数值类型

数值类型 int类型最大最小值 INT_MIN :最小值 INT_MAX &#xff1a;最大值unsigned int 类型最大是&#xff1a; UINT_MAXlong类型的最大最小 LONG_MIN LONG_MAX 无符号的long类型大小 ULONG_MAXlong long 类型大小 LLONG_MIN LLONG_MAX 无符号类型 ULLONG_MAX 整型&am…

npm常用命令系统介绍

npm常用命令系统介绍 npm helpnpm initpackage.json 文件package.json 文件属性说明默认 package.json 文件--参数[-yes|-y]设置 package.json 中字段的默认值package-lock.json 文件 npm [config|c]设置源 npm [install|i]可选参数&#xff1a;全局安装的特性 包的删除npm uni…

蓝桥杯 题库 简单 每日十题 day1

01 空间 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 小蓝准备用 256MB 的内存空间开一个数组&#xff0c;数组的每个元素都是 32 位 二进制整数&#xff0c;如果不考虑程序占用的空间和维护内存需要的辅助空间&#xff…

设置HTTP代理隧道

在网络世界中&#xff0c;使用HTTP代理IP可以帮助我们实现一些有趣的功能&#xff0c;比如突破网络封锁、访问被限制的内容、隐藏真实IP等。现在&#xff0c;我将为你详细介绍如何设置HTTP代理服务器&#xff0c;让你轻松掌握这项技能&#xff01; 步骤一&#xff1a;了解HTTP…

腾讯mini项目-【指标监控服务重构】2023-08-17

今日已办 定位昨日发现的问题 来回测试发现依然出现该问题 将 pub/sub 的库替换为原来官方基于 sarama 的实现&#xff0c;发现问题解决了&#xff0c;所以问题的根本是 kafkago 这个库本身存在问题 依据官方的实现&#xff0c;尝试自定义实现 pub/sub sarama 与 kafka-go …

【Java 基础篇】深入了解Java的File类:文件和目录操作指南

在Java编程中&#xff0c;处理文件和目录是一项常见的任务。Java提供了java.io.File类&#xff0c;用于在文件系统中创建、访问和操作文件和目录。本文将深入探讨Java的File类&#xff0c;向您介绍如何使用它来进行文件和目录的操作&#xff0c;从基础到高级的用法都将一一介绍…

Visual Studio 调试上传文件时自动停止运行的解决方法

进入&#xff1a;选项&#xff0c;项目和解决方案&#xff0c;Web项目&#xff0c; 找到在浏览器窗口关闭时停止调试程序&#xff0c;在调试停止时关闭浏览器 将它不要勾关闭&#xff0c;然后重新启动下Visual Studio&#xff0c;上传文件时就可以调试了

Windows 打包 Docker 提示环境错误: no DOCKER_HOST environment variable

这个问题应该还是比较常见的。 [ERROR] Failed to execute goal io.fabric8:docker-maven-plugin:0.40.2:build (default) on project mq-service: Execution default of goal io.fabric8:docker-maven-plugin:0.40.2:build failed: No <dockerHost> given, no DOCKER_H…

机器视觉Halcon-焊点提取排序设计思路一

目录 一.内容提要①本文是Blob示例之一,利用二值化原理阈值分割的方法,进行焊点检出的思路。二.问题分析及设计思路①.对图形窗口字体设置②.通过亮背景提取暗特征,提取焊点③.图像处理④.显示排序数字一.内容提要 ①本文是Blob示例之一,利用二值化原理阈值分割的方法,进…

GIS前端—Popup标注视图

GIS前端—Popup标注视图 Popup标注视图聚合标注 Popup标注视图 即根据需求实现个性化的弹框标注视图。Leaflet提供了L.Popup对象&#xff0c;用于添加Popup标注视图&#xff0c;通过setLatLng()方法设置Popup标注视图的位置&#xff0c;通过setContent()方法设置Popup标注视图…