代碼隨想錄算法訓練營Day22|235.二叉搜索樹的最近公共祖先、701.二叉搜索樹中的插入操作、450.刪除二叉搜索樹中的節點

二叉搜索樹的最近公共祖先

不考慮二叉搜索樹這一條件的話,普通的二叉搜索樹搜索最近的公共祖先就是昨日的做法,這種做法也能解決二叉搜索樹的最近公共祖先。

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {// 如果當前節點為空,或者等于p或q,直接返回當前節點if (root == nullptr || root == p || root == q) {return root;}// 在左右子樹中遞歸尋找p和qTreeNode* left = lowestCommonAncestor(root->left, p, q);TreeNode* right = lowestCommonAncestor(root->right, p, q);// 如果左右子樹的返回值都不為空,說明當前節點就是最近公共祖先if (left != nullptr && right != nullptr) {return root;}// 否則,返回非空的子樹返回值return left != nullptr ? left : right;}
};

沒有用上二叉搜索樹這一條件,但也能解題,但效率較低。

針對二叉搜索樹,我們之前有做過,當對二叉搜索樹進行中序編歷時,結果是一個遞增的數組。即公共祖先,val值必定處于p和q之間。

當從根節點向下遍歷的過程中,如果遇到節點val值位于p和q之間,那么就尋找到了最近的公共祖先。具體參考代碼隨想錄B站視頻。

二叉搜索樹找祖先就有點不一樣了!| 235. 二叉搜索樹的最近公共祖先_嗶哩嗶哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1Zt4y1F7ww/?spm_id_from=333.788&vd_source=fc4a6e70e3a87b7ea67c2024e326e7c5從上到下遍歷,考慮層序遍歷的方式,具體代碼如下:

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {queue<TreeNode*>queue;if(root == nullptr){return nullptr;}queue.push(root);TreeNode*cur = root;int min = p->val>q->val?q->val:p->val;//找到p,q中val的較小值int max = p->val<q->val?q->val:p->val;//找到p,q中val的較大值while(!queue.empty()){//層序遍歷過程int level_size = queue.size();for(int i = 0; i <level_size; i ++){cur = queue.front();queue.pop();if(cur->val<=max and cur->val>=min){return cur;}//找到節點屬于p,q間則返回if(cur->left)queue.push(cur->left);if(cur->right)queue.push(cur->right);} }return nullptr;}
};

算法的時間復雜度和空間復雜度均為O(n)。

前序遞歸,中左右,參考代碼隨想錄

代碼隨想錄 (programmercarl.com)icon-default.png?t=N7T8https://programmercarl.com/0235.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88.html#%E6%80%9D%E8%B7%AF

class Solution {
private:TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q) {if (cur == NULL) return cur;// 中if (cur->val > p->val && cur->val > q->val) {   // 左TreeNode* left = traversal(cur->left, p, q);if (left != NULL) {return left;}}if (cur->val < p->val && cur->val < q->val) {   // 右TreeNode* right = traversal(cur->right, p, q);if (right != NULL) {return right;}}return cur;}
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {return traversal(root, p, q);}
};

二叉搜索樹中的插入操作

由于樹中的節點值是獨一無二的,在二叉搜索樹中尋找值應插入的節點的父節點位置,然后創建一個新節點并將其插入即可。

代碼整體如下

class Solution {
public:// 在二叉搜索樹中查找適合插入新節點的位置,并返回該位置的父節點TreeNode* findBST(TreeNode* root, int val) {// 如果當前節點為空,返回nullptr,表示沒有找到合適的插入位置if (root == nullptr) return nullptr;// 如果val小于當前節點的值,應該在左子樹中繼續查找if (val < root->val) {// 如果左子節點為空,當前位置就是適合插入新節點的位置if (root->left == nullptr) return root;// 否則,在左子樹中繼續查找return findBST(root->left, val);} else {// 如果val大于或等于當前節點的值,應該在右子樹中繼續查找// 如果右子節點為空,當前位置就是適合插入新節點的位置if (root->right == nullptr) return root;// 否則,在右子樹中繼續查找return findBST(root->right, val);}}// 在二叉搜索樹中插入一個新的節點TreeNode* insertIntoBST(TreeNode* root, int val) {// 創建新節點TreeNode* newnode = new TreeNode(val);// 如果樹為空,新節點即為根節點if (root == nullptr) {return newnode;}// 查找適合插入新節點的位置,并得到該位置的父節點TreeNode* parent = findBST(root, val);// 根據val的值決定新節點是作為左子節點還是右子節點if (val < parent->val) {parent->left = newnode;} else {parent->right = newnode;}// 返回根節點return root;}
};

算法的時間復雜度為O(logn)(二叉搜索樹,最差為O(n)),空間復雜度為O(1)。

刪除二叉搜索樹中的節點

有五種情況

1.未找到需要刪除的節點

2.刪除的是葉節點

3.刪除的節點僅有右子樹

4.刪除的節點僅有左子樹

5.刪除的節點左右子樹都在

針對這五種情況,有以下五種解答方案

1.直接返回二叉搜索樹的根節點

2.直接刪除即可

3.將右孩子代替被刪除的節點

4.將左孩子代替被刪除的節點

5.有兩種解決方式,分別是讓被刪除節點的右孩子或左孩子即位,以右孩子即位,查找右子樹下的最小值節點,將節點的左子樹全部接入該節點,或以左孩子即位,查找左子樹下的最大值節點,將節點的右子樹全部接入該節點。

class Solution {
public:TreeNode* find_parent(TreeNode* root, int key) {if (root == nullptr || (root->left == nullptr && root->right == nullptr)) {return nullptr; // 如果當前節點為空或為葉節點,返回nullptr}if (root->left != nullptr && root->left->val == key) {return root; // 如果左子節點的值等于key,返回當前節點作為父節點}if (root->right != nullptr && root->right->val == key) {return root; // 如果右子節點的值等于key,返回當前節點作為父節點}if (key < root->val) {return find_parent(root->left, key); // 如果key小于當前節點的值,遞歸地在左子樹中查找} else {return find_parent(root->right, key); // 如果key大于或等于當前節點的值,遞歸地在右子樹中查找}}TreeNode* deleteNode(TreeNode* root, int key) {if (root == nullptr) return nullptr;if (root->val == key) {// 要刪除的節點是根節點if (root->left == nullptr) return root->right; // 只有右子樹if (root->right == nullptr) return root->left; // 只有左子樹// 有兩個子節點,找到右子樹的最小節點TreeNode* minNode = getMin(root->right);root->val = minNode->val; // 將右子樹的最小節點的值賦給當前節點root->right = deleteNode(root->right, minNode->val); // 刪除右子樹中的最小節點} else if (key < root->val) {root->left = deleteNode(root->left, key); // 在左子樹中遞歸刪除} else {root->right = deleteNode(root->right, key); // 在右子樹中遞歸刪除}return root;}TreeNode* getMin(TreeNode* node) {while (node->left != nullptr) node = node->left;return node;}
};

算法的時間復雜度需要考慮樹的高度,查找樹中要刪除的節點,需要O(logn)的時間,當需要刪除的節點有兩個子節點時,需要找到右子樹中的最小節點,這同樣需要O(logn)的時間,最壞情況下時間復雜度為O(logn)。

空間復雜度主要取決于遞歸棧的深度,因此,空間復雜度也為O(logn)。

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

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

相關文章

貪心算法02(leetcode122/55/4)

參考資料&#xff1a; https://programmercarl.com/0122.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAII.html 122. 買賣股票的最佳時機 II 題目描述&#xff1a; 給你一個整數數組 prices &#xff0c;其中 prices[i] 表示某支股票第…

STM32讀寫內部FLASH讀取芯片id

文章目錄 讀寫內部Flash接線程序編寫測試效果補充 讀取芯片id代碼編寫 讀寫內部Flash 接線 程序編寫 首先使用ThisFlash.c來寫入flash的基本操作&#xff0c;寫入、讀取、擦除&#xff0c;然后使用Store.c配合數組來進行主存與flash的交互 ThisFlash.c #include "stm32…

為什么工控現場會用到Profinet轉Modbus網關設備

一、背景&#xff1a; 工控現場之所以需要使用Profinet轉Modbus網關&#xff0c;是因為工控系統中常常存在不同廠家設備之間通訊協議不一致的問題。而Modbus和Profinet分別代表著兩種不同的通信協議&#xff0c;Profinet通常用于較新的設備&#xff0c;而Modbus則是比較老的通…

思科防火墻ASA Version 9.1(1) 怎么配置靜態NAT,把內網ip192.168.1.10 端口1000映射到公網端口1000上?

環境: 思科防火墻5520 ASA Version 9.1(1) 問題描述: 思科防火墻ASA Version 9.1(1) 怎么配置靜態NAT,把內網ip192.168.1.10 端口1000映射到公網端口1000上? 解決方案: 舊版本8.0 1.做之前要先查一下有沒有端口被占用,要和業務確認2.sh Xlate | in 10011 端口 這條…

ch2應用層--計算機網絡期末復習

2.1應用層協議原理 網絡應用程序位于應用層 開發網絡應用程序: 寫出能夠在不同的端系統上通過網絡彼此通信的程序 2.1.1網絡應用程序體系結構分類: 客戶機/服務器結構 服務器: 總是打開(always-on)具有固定的、眾所周知的IP地址 主機群集常被用于創建強大的虛擬服務器 客…

MongoDB CRUD操作:快照查詢

MongoDB CRUD操作&#xff1a;快照查詢 文章目錄 MongoDB CRUD操作&#xff1a;快照查詢對比本地和快照的讀關注舉例從相同的時間點運行查詢從過去某個時刻讀取數據的一致狀態 配置快照保留時間磁盤空間和歷史記錄 使用快照查詢可以讀取最近某個時間點的數據&#xff0c;而且從…

基于51單片機的溫控風扇的設計–仿真設計

可實現通過DS18B20測量當前環境溫度 可實現通過溫度自動控制風扇轉速 可實現通過按鍵設置不同風速對應的溫度 可實現通過按鍵切換自動、手動模式 可實現在手動模式下通過按鍵調整風扇轉速 可實現通過LCD1602顯示溫度、風扇轉速擋位、自動/手動模式

【C++】模擬實現string類

&#x1f984;個人主頁:修修修也 &#x1f38f;所屬專欄:C ??操作環境:Visual Studio 2022 目錄 一.了解項目功能 二.逐步實現項目功能模塊及其邏輯詳解 &#x1f38f;構建成員變量 &#x1f38f;實現string類默認成員函數 &#x1f4cc;構造函數 &#x1f4cc;析構函數…

k8s 全面掌控日志系統

概述 為了提高系統運維和故障排查的效率&#xff0c; 日志系統采用 ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;技術棧&#xff0c;通過 FileBeats 作為日志收集器&#xff0c;將來自不同節點的日志數據匯總并存儲在 Elasticsearch 中&#xff0c;最終通過 K…

創建一個新的Spring Security應用程序,并使用JDBC連接數據庫

創建一個新的Spring Security應用程序&#xff0c;并使用JDBC連接數據庫 在這個教程中&#xff0c;我們將學習如何創建一個新的Spring Security應用程序&#xff0c;使用JDBC連接數據庫以獲取用戶信息并進行認證。我們還將學習如何配置Spring Security以從數據庫中獲取用戶和權…

Vue3使用Composition API實現響應式

title: Vue3使用Composition API實現響應式 date: 2024/5/29 下午8:10:24 updated: 2024/5/29 下午8:10:24 categories: 前端開發 tags: Vue3CompositionRefsReactiveWatchLifecycleDebugging 1. 介紹 Composition API是Vue.js 3中新增的一組API&#xff0c;用于在組件中組…

SQL 語言:嵌入式 SQL 和動態 SQL

文章目錄 基本概述嵌入式 SQL動態 SQL總結 基本概述 嵌入式SQL和動態SQL是兩種在應用程序中嵌入和使用SQL語句的方法。它們都允許開發人員在編程語言中編寫SQL語句&#xff0c;以便在應用程序中執行數據庫操作。然而&#xff0c;這兩種方法在實現方式、性能和靈活性方面存在一…

Java數據結構與算法(紅黑樹)

前言 紅黑樹是一種自平衡二叉搜索樹&#xff0c;確保在插入和刪除操作后&#xff0c;樹的高度保持平衡&#xff0c;從而保證基本操作&#xff08;插入、刪除、查找&#xff09;的時間復雜度為O(log n)。 實現原理 紅黑樹具有以下性質&#xff1a; 每個節點要么是紅色&#…

go語言學習之旅之Go結構體

在Go語言中&#xff0c;結構體&#xff08;struct&#xff09;是一種用戶定義的數據類型&#xff0c;用于組合不同類型的數據項。結構體可以包含其他結構體或基本數據類型的字段。以下是關于Go語言結構體的基本知識&#xff1a; 定義結構體&#xff1a; package mainimport &…

Python 之微信指數小程序數據抓取

Fiddler安裝和設置 安裝 Fiddler 安裝包可以從這里獲取&#xff0c;如果失效了可以自己網上找一個安裝。 鏈接&#xff1a;https://pan.baidu.com/s/1N30BoDWm2_dBL8i8GRzK5g?pwd1znv 提取碼&#xff1a;1znv 然后就是點擊安裝就好了&#xff0c;沒什么好多說的。 啟用…

刷代碼隨想錄有感(83):貪心算法——最大子數組和

題干&#xff1a; 代碼&#xff1a; class Solution { public:int maxSubArray(vector<int>& nums) {int res INT_MIN;int count 0;for(int i 0; i < nums.size(); i){count nums[i];if(count > res) res count;if(count < 0)count 0;}return res;} …

【創作活動】探索 GPT-4o:下一代語言模型的技術革命

&#x1f604; 19年之后由于某些原因斷更了三年&#xff0c;23年重新揚帆起航&#xff0c;推出更多優質博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有堅忍不拔之志 &#x1f390; 個人CSND主頁——Mi…

HTTP報文

HTTP報文 報文流 HTTP報文是在HTTP引用程序之間發送的數據塊&#xff0c;這些數據塊以一種文本形式的元信息開頭&#xff0c;這些信息描述了報文的內容和含義&#xff0c;后面跟著可選的數據部分&#xff0c;這些報文在客戶端&#xff0c;服務器和代理之間流動。 報文流入源…

git更改本地項目關聯到新倉庫

刪除現在遠程關聯的倉庫 git remote rm origin鏈接新倉庫 git remote add origin url(需要關聯的新倉庫地址)代碼提交到遠程倉庫master分支 git push --set-upstream origin master本地分支更新同步至遠程倉庫 比如本地有dev分支 git push origin dev:dev

前端項目開發,3個HTTP請求工具

這一小節&#xff0c;我們介紹一下前端項目開發中&#xff0c;HTTP請求會用到的3個工具&#xff0c;分別是fetch、axios和js-tool-big-box中的jsonp請求。那么他們都有哪些小區別呢&#xff1f;我們一起來看一下。 目錄 1 fetch 2 axios 3 js-tool-big-box 的 jsonp 請求 …