LeetCode450. 刪除二叉搜索樹中的節點

450. 刪除二叉搜索樹中的節點

文章目錄

      • [450. 刪除二叉搜索樹中的節點](https://leetcode.cn/problems/delete-node-in-a-bst/)
        • 一、題目
        • 二、題解
          • 方法一:遞歸(一種麻煩的方法)
          • 方法二:優化后的遞歸


一、題目

給定一個二叉搜索樹的根節點 root 和一個值 key,刪除二叉搜索樹中的 key 對應的節點,并保證二叉搜索樹的性質不變。返回二叉搜索樹(有可能被更新)的根節點的引用。

一般來說,刪除節點可分為兩個步驟:

  1. 首先找到需要刪除的節點;
  2. 如果找到了,刪除它。

示例 1:

img

輸入:root = [5,3,6,2,4,null,7], key = 3
輸出:[5,4,6,2,null,null,7]
解釋:給定需要刪除的節點值是 3,所以我們首先找到 3 這個節點,然后刪除它。
一個正確的答案是 [5,4,6,2,null,null,7], 如下圖所示。
另一個正確答案是 [5,2,6,null,4,null,7]。

示例 2:

輸入: root = [5,3,6,2,4,null,7], key = 0
輸出: [5,3,6,2,4,null,7]
解釋: 二叉樹不包含值為 0 的節點

示例 3:

輸入: root = [], key = 0
輸出: []

提示:

  • 節點數的范圍 [0, 104].
  • -105 <= Node.val <= 105
  • 節點值唯一
  • root 是合法的二叉搜索樹
  • -105 <= key <= 105

進階: 要求算法時間復雜度為 O(h),h 為樹的高度。

二、題解

方法一:遞歸(一種麻煩的方法)

主要思路如下:

  1. findNode 函數:這個函數用于在給定的二叉搜索樹中找到值等于 target 的節點。函數采用遞歸的方式,在樹中搜索目標節點。如果當前節點為空,說明未找到目標節點,返回 nullptr。如果當前節點的值等于目標值,返回該節點。如果當前節點的值大于目標值,說明目標節點在左子樹中,遞歸地搜索左子樹。否則,目標節點在右子樹中,遞歸地搜索右子樹。

  2. deleteNode 函數:這個函數用于刪除二叉搜索樹中值為 key 的節點。首先,通過調用 findNode 函數找到待刪除的節點 node,同時維護一個指向 node 的父節點 pre。然后根據刪除情況進行不同的處理:

    • 如果 pre 為空,說明待刪除節點是根節點。然后根據左右子樹的情況進行調整,保留右子樹并將左子樹插入右子樹中的最左葉子節點。
    • 如果 pre 非空,根據 pre 的位置判斷 node 是其父節點的左子節點還是右子節點。然后根據左右子樹的情況進行調整,同樣保留右子樹并將左子樹插入右子樹中的最左葉子節點。

最后,刪除 node 節點并返回調整后的樹。

/*** Definition for a binary tree node.* 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 *pre = nullptr;TreeNode* findNode(TreeNode *root, int target){if(root == nullptr){return root;}if(root->val == target){return root;}pre = root;if(root->val > target){TreeNode *left = findNode(root->left, target);return left;}else{TreeNode *right = findNode(root->right, target);return right;}}TreeNode* deleteNode(TreeNode* root, int key) {TreeNode *node = findNode(root, key);if(node == nullptr) return root;if(pre == nullptr){if(node->left && node->right){TreeNode *temp = node->right;while(temp->left){temp = temp->left;}temp->left = node->left;return node->right;}else if(node->left){return node->left;}else if(node->right){return node->right;}else{return nullptr;}}if(pre && pre -> right == node){if(node->left && node->right){TreeNode *temp = node->right;while(temp->left){temp = temp->left;}temp->left = node->left;pre->right = node->right;}else if(node->left){pre->right = node->left;}else if(node->right){pre->right = node->right;}else{pre->right = nullptr;}}if(pre && pre->left == node){if(node->left && node->right){TreeNode *temp = node->right;while(temp->left){temp = temp->left;}temp->left = node->left;pre->left = node->right;}else if(node->left){pre->left = node->left;}else if(node->right){pre->left = node->right;}else{pre->left = nullptr;}}delete node;return root;}
};
方法二:優化后的遞歸

算法思路

  1. 遞歸搜索節點: 首先,我們從根節點開始遞歸地搜索目標節點(值為key的節點)。

    • 如果當前節點為空,表示沒有找到目標節點,直接返回空指針(nullptr)。
    • 如果當前節點的值大于目標key,說明目標節點在左子樹中,遞歸搜索左子樹。
    • 如果當前節點的值小于目標key,說明目標節點在右子樹中,遞歸搜索右子樹。
    • 如果當前節點的值等于目標key,說明找到了目標節點,繼續下一步。
  2. 處理刪除操作: 一旦我們找到了目標節點,有幾種情況需要處理:

    • 如果目標節點沒有左子樹,那么我們可以用其右子樹來替代這個節點,然后刪除這個節點。
    • 如果目標節點沒有右子樹,類似地,我們可以用其左子樹來替代這個節點,然后刪除這個節點。
    • 如果目標節點既有左子樹又有右子樹,我們可以找到其右子樹中最小的節點(即右子樹中的最左節點,即后繼節點),將該節點的值復制到目標節點上,然后遞歸地在右子樹中刪除這個后繼節點。
  3. 返回根節點: 最后,無論如何都要返回當前子樹的根節點。

具體實現

class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {if (!root)return nullptr;if (root->val > key) {root->left = deleteNode(root->left, key); // 遞歸搜索左子樹} else if (root->val < key) {root->right = deleteNode(root->right, key); // 遞歸搜索右子樹} else {if (!root->left) { // 沒有左子樹,用右子樹替代TreeNode* temp = root->right;delete root;return temp;} else if (!root->right) { // 沒有右子樹,用左子樹替代TreeNode* temp = root->left;delete root;return temp;}TreeNode* temp = findMin(root->right); // 找到后繼節點root->val = temp->val;root->right = deleteNode(root->right, temp->val); // 在右子樹中刪除后繼節點}return root; // 返回根節點}private:TreeNode* findMin(TreeNode* node) {while (node->left)node = node->left;return node; // 找到最左節點,即后繼節點}
};

算法分析

  • 在最壞情況下,我們需要遍歷BST的高度h,即時間復雜度為O(h)。
  • 遞歸深度取決于樹的高度,所以空間復雜度也是O(h)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/42783.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/42783.shtml
英文地址,請注明出處:http://en.pswp.cn/news/42783.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot校驗,DTO文件中常用的注解應用案例.

在觀看本篇文章之前&#xff0c;可以先參考我之前寫的一篇文章 “ Spring5&#xff0c;Service層對DTO文件進行數據格式校驗. ” &#xff0c;這篇文章是介紹在 Service層 對DTO文件的校驗。 以下方的 CompanyDTO 文件為例&#xff0c;講解不同的注解使用場景&#xff0c;以及…

論文閱讀——Imperceptible Adversarial Attack via Invertible Neural Networks

Imperceptible Adversarial Attack via Invertible Neural Networks 作者&#xff1a;Zihan Chen, Ziyue Wang, Junjie Huang*, Wentao Zhao, Xiao Liu, Dejian Guan 解決的問題&#xff1a;雖然視覺不可感知性是對抗性示例的理想特性&#xff0c;但傳統的對抗性攻擊仍然會產…

每天一道leetcode:1129. 顏色交替的最短路徑(圖論中等廣度優先遍歷)

今日份題目&#xff1a; 給定一個整數 n&#xff0c;即有向圖中的節點數&#xff0c;其中節點標記為 0 到 n - 1。圖中的每條邊為紅色或者藍色&#xff0c;并且可能存在自環或平行邊。 給定兩個數組 redEdges 和 blueEdges&#xff0c;其中&#xff1a; redEdges[i] [ai, bi…

Dubbo Spring Boot Starter 開發微服務應用

環境要求 系統&#xff1a;Windows、Linux、MacOS JDK 8 及以上&#xff08;推薦使用 JDK17&#xff09; Git IntelliJ IDEA&#xff08;可選&#xff09; Docker &#xff08;可選&#xff09; 項目介紹 在本任務中&#xff0c;將分為 3 個子模塊進行獨立開發&#xff…

LINUX學習筆記_GIT操作命令

LINUX學習筆記 GIT操作命令 基本命令 git init&#xff1a;初始化倉庫git status&#xff1a;查看文件狀態git add&#xff1a;添加文件到暫存區&#xff08;index&#xff09;git commit -m “注釋”&#xff1a;提交文件到倉庫&#xff08;repository&#xff09;git log&a…

計算機組成與設計 Patterson Hennessy 筆記(一)MIPS 指令集

計算機的語言&#xff1a;匯編指令集 也就是指令集。本書主要介紹 MIPS 指令集。 匯編指令 算數運算&#xff1a; add a,b,c # abc sub a,b,c # ab-cMIPS 匯編的注釋是 # 號。 由于MIPS中寄存器大小32位&#xff0c;是基本訪問單位&#xff0c;因此也被稱為一個字 word。M…

Java Web常見面試題

1、JSP和Servlet有什么區別 jsp經過編譯后變成類Servlet&#xff08;JSP的本質就是Servelt&#xff0c;JVM只能識別java的類&#xff0c;不能識別jsp的代碼&#xff0c;于是web容器將jsp的代碼編譯成JVM能夠識別的java類&#xff0c;也就是servelt&#xff09;jsp更擅長表現于…

【2023年11月第四版教材】《第5章-信息系統工程之系統集成(第四部分)》

《第5章-信息系統工程之系統集成&#xff08;第四部分&#xff09;》 3 系統集成3.1網絡集成3.2 數據集成3.3 軟件集成3.4 應用集成3.5 安全工程 3 系統集成 3.1網絡集成 安全對策要點傳輸子系統1.常用的無線傳輸介質主要包括無線電波、微波、紅外線等2.常用的有線傳輸介質主…

webpack中常見的Loader

目錄 1.webpack中的loader是什么&#xff1f;配置方式 2. loader特性3.常見的loader 1.webpack中的loader是什么&#xff1f; loader 用于對模塊的"源代碼"進行轉換&#xff0c;在 import 或"加載"模塊時預處理文件 webpack做的事情&#xff0c;僅僅是分…

爬蟲逆向實戰(三)--天某云登錄

一、數據接口分析 主頁地址&#xff1a;天某云 1、抓包 通過抓包可以發現登錄接口是account/login 2、判斷是否有加密參數 請求參數是否加密&#xff1f; 通過“載荷”模塊可以發現password、comParam_signature、comParam_seqCode是加密的 請求頭是否加密&#xff1f; 無…

ElasticSearch 8.9.0 開發模式安裝

ElasticSearch 8.9.0 開發模式安裝 MacOS&#xff08;Apple芯片&#xff09;&#xff1a;https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.9.0-darwin-aarch64.tar.gz Linux&#xff1a;https://artifacts.elastic.co/downloads/elasticsearch/elasti…

git倉庫新建上傳記錄

新建git倉會出現版本分支問題&#xff0c;解決過程&#xff1a; 其他的前期綁定之類的傳送&#xff1a;https://blog.csdn.net/qq_37194189/article/details/130767397 大概思路&#xff1a;新建一個分支&#xff0c;上傳&#xff0c;合并&#xff0c;刪除分支 git branch …

4.2 C++ Boost 內存池管理庫

Boost 庫是一個由C/C語言的開發者創建并更新維護的開源類庫&#xff0c;其提供了許多功能強大的程序庫和工具&#xff0c;用于開發高質量、可移植、高效的C應用程序。Boost庫可以作為標準C庫的后備&#xff0c;通常被稱為準標準庫&#xff0c;是C標準化進程的重要開發引擎之一。…

cmake擴展(5)——file命令排除部分文件

在cmake中可以使用file命令獲取需要的文件&#xff0c;并且支持正則/通配符&#xff0c;使用起來還是很方便的。 #語法file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])#example file(GLOB_RECURSE SOURCES "src/*.h" "src/*.cp…

HTTP與HTTPS的區別

面試常見問題&#xff0c;HTTPS優化總結易記版&#xff1a; 1、HSTS重定向技術&#xff1a;將http自動轉換為https&#xff0c;減少301重定向 2、TLS握手優化&#xff1a;在TLS握手完成前客戶端就提前向服務器發送數據 3、會話標識符&#xff1a;服務器記錄下與某客戶端的會…

Mac鼠標增強工具Smooze Pro

Smooze Pro是一款Mac上的鼠標手勢增強工具&#xff0c;可以讓用戶使用鼠標手勢來控制應用程序和系統功能。 它支持多種手勢操作&#xff0c;包括單指、雙指、三指和四指手勢&#xff0c;并且可以自定義每種手勢的功能。例如&#xff0c;您可以使用單指向下滑動手勢來啟動Expos視…

Linux 僵死進程

fork復制進程之后&#xff0c;會產生一個進程叫做子進程&#xff0c;被復制的進程就是父進程。不管父進程先結束&#xff0c;還是子進程先結束&#xff0c;對另外一個進程完全沒有影響&#xff0c;父進程和子進程是兩個不同的進程。 一、孤兒進程 現在有以下代碼&#xff1a;…

如何計算全彩LED顯示屏的像素

大屏尺寸 提供大屏的尺寸和像素點間距&#xff0c;計算大屏的分辨率是多少&#xff1f; 大屏尺寸&#xff1a;寬度>10200mm&#xff0c;高度>2025mm&#xff1b;像素點間距<1.25mm 分辨率計算 寬10200/1.258160px 高2025/1.251620px 寬&#xff1a;高 接近 5:1&a…

PHP 三元 !empty 而不是評估為真或假 可用isset()

是否可以使用速記三元來檢查變量是否已設置&#xff0c;而不是是否計算結果為零或非零&#xff1f; 例如&#xff0c;我試過&#xff1a; $var 0; echo (string) $var ?: (string) false ?: 2;但由于前兩個表達式的計算結果均為“0”或“false”&#xff0c;因此顯示為 2。…

如何建立單元測試

快速開始 zixun-quickstart-mk3生成的項目已經配置好了基礎的BaseTest,各個測試類只需要繼承BaseTest就可以開始進行單元測試的編寫了。 如何進行Mock 為了保證獨立性和可重復執行,所有的外部依賴都需要進行Mock,SpringTest引入了Mockito作為單測Mock組件, Mickito官方文…