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

第二十天,二叉樹part07,二叉樹搜索樹加油加油💪

目錄

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

701.二叉搜索樹中的插入操作

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

拓展:普通二叉樹的刪除方式?

總結


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

文檔講解:代碼隨想錄二叉搜索樹的最近公共祖先

視頻講解:手撕二叉搜索樹的最近公共祖先

題目:

學習:

昨天我們是在普通二叉樹內找到公共祖先,采取的是后序遍歷的方式,遍歷所有的節點,直到找到目標值為止進行返回。

但本題是二叉搜索樹,我們可以利用二叉搜索樹的特點來進行公共祖先的查找。我們知道二叉搜索樹中每個節點的左子樹中的所有值一定小于該節點,右子樹中的所有值一定大于該節點。依據此特點我們可以把遍歷過程分為三種情況。

  1. p節點的值和q節點的值都小于當前遍歷節點的值,則在當前節點的左子樹進行尋找。
  2. p節點的值和q節點的值都大于當前遍歷節點的值,則在當前節點的右子樹進行尋找。
  3. p節點的值和q節點的值其中一個等于當前遍歷節點的值,或者分別大于,小于當前遍歷節點的值,則立馬返回當前遍歷的節點,該節點就是最小公共祖先。原因:①如果當前節點是p節點或者q節點的其中一個,由于我們是從上至下遍歷的,因此剩下一個節點肯定在該節點的子樹中,因此當前節點就是最小公共祖先。②當前節點不是p節點或者q節點,此時由于p節點和q節點分別位于當前節點的左右子樹之中,因此當前節點肯定是最小公共祖先,否則往左遍歷將錯過右子樹中的節點,往右遍歷將錯過左子樹中的節點。

代碼:遞歸法

//時間復雜度O(n)
//空間復雜度O(n)
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);return left;}else if (cur->val < p->val && cur->val < q->val) {   // 右TreeNode* right = traversal(cur->right, p, q);return right;}else { //第三種情況return cur;}}
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {return traversal(root, p, q);}
};

代碼:迭代法

//時間復雜度O(n)
//空間復雜度O(1)
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if (root == NULL) return NULL;TreeNode* answer = root; //返回數組while(answer) {//依據二叉搜索樹的特點,分為三種情況if(p->val > answer->val && q->val > answer->val) {answer = answer->right;}else if(p->val < answer->val && q->val < answer->val) {answer = answer->left;}else { //第三種情況break;}}return answer;}
};

701.二叉搜索樹中的插入操作

文檔講解:代碼隨想錄二叉搜索樹中的插入操作

視頻講解:手撕二叉搜索樹中的插入操作

題目:

學習:對于二叉搜索樹來說只要插入的數據和原始二叉樹中的節點不同,則肯定能插入樹中并成為一個葉子節點。本題其實不用考慮題目中的改變樹的結構的插入方式。

代碼:遞歸法(本題需要插入節點并將更改后的樹層層返回)

//時間復雜度O(n)
//空間復雜度O(n)
class Solution {
public:TreeNode* insertIntoBST(TreeNode* root, int val) {//確定終止條件if (root == nullptr) {TreeNode* node = new TreeNode(val);return node; //把新加入的節點進行返回}//確定單層遞歸邏輯if(root->val > val) {root->left = insertIntoBST(root->left, val);  //把更改后的樹一層層往上返回}if(root->val < val) {root->right = insertIntoBST(root->right, val); //把更改后的樹一層層往上返回}return root;}
};

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

文檔講解:代碼隨想錄刪除二叉搜索樹中的節點

視頻講解:手撕刪除二叉搜索樹中的節點

題目:?

學習:

本題需要刪除二叉搜索樹的節點,我們首先要分析的是,刪除的情況有哪些:

  1. 要刪除的節點在二叉樹中不存在,二叉樹不需要修改。
  2. 要刪除的是葉子節點,那直接刪除葉子節點,返回nullptr即可。
  3. 要刪除的是中間節點,但中間節點左孩子為空,右孩子不為空,讓右孩子替代刪除節點。
  4. 要刪除的是中間節點,但中間節點右孩子為空,左孩子不為空,讓左孩子替代刪除節點。
  5. 要刪除的節點中左右孩子都不為空,則可以將刪除節點的左子樹的頭節點(左孩子)放到刪除節點的右子樹的最左面節點的左孩子上,返回刪除節點右孩子為新的根節點。(補充一種我采取的方式,使用刪除節點的后繼或者前序來替代刪除節點,但處理會復雜一些)

第5中情況動畫說明:

代碼:遞歸法

//時間復雜度O(n)
//空間復雜度O(n)
class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {if (root == nullptr) return root; // 第一種情況:沒找到刪除的節點,遍歷到空節點直接返回了if (root->val == key) {// 第二種情況:左右孩子都為空(葉子節點),直接刪除節點, 返回NULL為根節點if (root->left == nullptr && root->right == nullptr) {///! 內存釋放delete root;return nullptr;}// 第三種情況:其左孩子為空,右孩子不為空,刪除節點,右孩子補位 ,返回右孩子為根節點else if (root->left == nullptr) {auto retNode = root->right;///! 內存釋放delete root;return retNode;}// 第四種情況:其右孩子為空,左孩子不為空,刪除節點,左孩子補位,返回左孩子為根節點else if (root->right == nullptr) {auto retNode = root->left;///! 內存釋放delete root;return retNode;}// 第五種情況:左右孩子節點都不為空,則將刪除節點的左子樹放到刪除節點的右子樹的最左面節點的左孩子的位置// 并返回刪除節點右孩子為新的根節點。else {TreeNode* cur = root->right; // 找右子樹最左面的節點while(cur->left != nullptr) {cur = cur->left;}cur->left = root->left; // 把要刪除的節點(root)左子樹放在cur的左孩子的位置TreeNode* tmp = root;   // 把root節點保存一下,下面來刪除root = root->right;     // 返回舊root的右孩子作為新rootdelete tmp;             // 釋放節點內存(這里不寫也可以,但C++最好手動釋放一下吧)return root;}}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)
class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {//確定終止條件//沒有找到的話if(root == nullptr) return root;//找到了的話,分為4種情況if(root->val == key) {//第一種情況,要刪除的是葉子節點,則直接返回空if(root->left == nullptr && root->right == nullptr) {//內存釋放delete root;return nullptr;}//第二種情況,要刪除的是中間節點,但是左子樹為空,使用右子樹節點替代else if(root->left == nullptr && root->right != nullptr) {TreeNode* tmp = root;root = root->right;delete tmp;return root;}//第三種情況,要刪除的是中間節點,但是右子樹為空,使用左子樹節點替代else if(root->left != nullptr && root->right == nullptr) {TreeNode* tmp = root;root = root->left;delete tmp;return root;}//第四種情況,要刪除的是中間節點,且左右子樹都不為空//使用前驅或者后繼節點替代else {//使用后繼節點替代,即右子樹的最左邊的節點。TreeNode* cur = root->right; TreeNode* pre = nullptr; //指向cur的前一個節點while(cur->left != nullptr ) {pre = cur;cur = cur->left;}if(pre == nullptr) { //說明一次循環沒有進行,刪除節點的右子樹的根節點沒有左邊部分,則其自身就是刪除節點的后繼cur->left = root->left; //把刪除節點的左子樹保留delete root;return cur;}else { //說明至少進入了循環一次pre->left = cur->right; //先把cur分理出,并保存cur的右子樹(可能為空)cur->left = root->left; //將刪除節點的左右子樹釋放cur->right = root->right;delete root;return cur;}}}root->left = deleteNode(root->left, key);root->right = deleteNode(root->right, key);return root;}
};

拓展:普通二叉樹的刪除方式?

學習:對于普通二叉樹的節點刪除來說,可以通過和葉子節點交換值得方式,然后再進行刪除。

代碼中目標節點(要刪除的節點)被操作了兩次:第一次是和目標節點的右子樹最左面節點交換。第二次直接被NULL覆蓋了。

代碼:

class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {if (root == nullptr) return root;if (root->val == key) {if (root->right == nullptr) { // 這里第二次操作目標值:最終刪除的作用return root->left;}TreeNode *cur = root->right;while (cur->left) {cur = cur->left;}swap(root->val, cur->val); // 這里第一次操作目標值:交換目標值其右子樹最左面節點。}root->left = deleteNode(root->left, key);root->right = deleteNode(root->right, key);return root;}
};

總結

二叉搜索樹的特點要牢記,利用好二叉樹的特點能夠更有效的進行算法設計。

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

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

相關文章

潔凈室(區)浮游菌檢測標準操作規程及GB/T 16292-2010測試方法解讀

潔凈室(區)空氣中浮游菌的檢測。潔凈區浮游菌檢測是一種評估和控制潔凈區(如實驗室、生產車間等)內空氣質量的方法。這種檢測的目的是通過測量空氣中的微生物(即浮游菌)數量&#xff0c;來評估潔凈區的清潔度或污染程度。下面中邦興業小編帶大家詳細看下如何進行浮游菌采樣檢測…

RK3568技術筆記九 編譯Linux詳細介紹

在編譯前需要按照前面的方法始化編譯環境&#xff0c;否則會導致編譯失敗&#xff08;若配置過則無需重復配置&#xff09;。 全自動編譯包含所有鏡像編譯&#xff0c;包括&#xff1a;uboot編譯、Kernel編譯、Recovey編譯、文件系統編譯、編譯完成鏡像的更新與打包。 按照前面…

閱讀筆記——《Large Language Model guided Protocol Fuzzing》

【參考文獻】Meng R, Mirchev M, Bhme M, et al. Large language model guided protocol fuzzing[C]//Proceedings of the 31st Annual Network and Distributed System Security Symposium (NDSS). 2024.&#xff08;CCF A類會議&#xff09;【注】本文僅為作者個人學習筆記&a…

【附精彩文章合輯】當談到程序的“通用性”與“過度設計”的困境時,我們可以通過一些具體的例子來更直觀地闡述這些解決方案

當談到程序的“通用性”與“過度設計”的困境時&#xff0c;我們可以通過一些具體的例子來更直觀地闡述這些解決方案。以下是一些示例&#xff1a; 一、明確需求與目標 例子1&#xff1a;在線購物平臺 需求分析&#xff1a;平臺需要支持用戶注冊、登錄、瀏覽商品、下單購買、…

2024ciscn 華東北awdp pwn部分wp

pwn1 break 很簡單&#xff0c;棧可執行。 先格式化字符串泄露出棧地址和canary&#xff0c;然后稍稍布置一下打orw就行 沙盒和沒有一樣 from pwn import *context(archamd64, oslinux)if __name__ __main__:# io remote(192.47.1.39, 80)io remote(192.168.142.137, 123…

初階 《操作符詳解》 10. 逗號表達式

10. 逗號表達式 exp1, exp2, exp3, …expN 注&#xff1a; 1.逗號表達式&#xff0c;就是用逗號隔開的多個表達式 2.逗號表達式&#xff0c;從左向右依次執行&#xff0c;整個表達式的結果是最后一個表達式的結果 代碼1 #include <stdio.h> int main() {int a 1;int b…

【Qt6.3 基礎教程 19】 設計直觀用戶界面(UI):Qt應用界面設計原則

文章目錄 前言理解用戶需求界面的簡潔性一致性反饋利用布局管理美化你的應用結論 前言 用戶界面(UI)設計對于任何軟件項目的成功至關重要&#xff0c;因為它是用戶與您的應用之間交流的橋梁。在Qt環境中&#xff0c;擁有一套清晰和直觀的UI設計原則&#xff0c;將有助于您創建…

解決ubuntu18.04 安裝vscode 報依賴庫錯誤,以及打不開終端的問題。

其實很簡單&#xff0c;ubuntu18.04太老了&#xff0c;官網最新版本的vscode對ubuntu18.04會有些依賴庫的問題。 一頓查資料后發現2023.11月的1.85版本正常使用&#xff0c;于是完美解決。 下載鏈接 Visual Studio Code November 2023 點擊這里下載。 下載完成&#xff0c;…

golang 獲取字符串切割之后的最后一個字符串

有些場景需要獲取字符串按某個字符切割之后&#xff0c;獲取最后&#xff0c;有個比較好的實踐分享 strings.LastIndex 如果沒有匹配到&#xff0c;則返回-1 package mainimport ("fmt""strings" )func main() {ss : []string{"", ":&quo…

數據結構需要每個都具體實現嗎?

在開始前剛好我有一些資料&#xff0c;是我根據網友給的問題精心整理了一份「數據結構的資料從專業入門到高級教程」&#xff0c; 點個關注在評論區回復“666”之后私信回復“666”&#xff0c;全部無償共享給大家&#xff01;&#xff01;&#xff01;用c的stl能刷算法題是不…

【INTEL(ALTERA)】運行配置找不到導入的自定義 makefile 項目

目錄 說明 解決方法 說明 在使用 Import Custom Makefile 用于Nios II軟件構建工具項目 選項導入項目后&#xff0c;Nios II SBT 無法將導入的自定義 makefile 識別為Nios II C/C 應用項目。因此&#xff0c;項目名稱不出現在運行配置中的列表中。 解決方法 在 "運行配置 …

clean code-代碼整潔之道 閱讀筆記(第十三章)

第十三章 并發編程 "對象是過程的抽象。線程是調度的抽象。" --James O Coplien 13.1 為什么要并發 并發是一種解耦策略。它幫助我們把做什么&#xff08;目的&#xff09;和何時&#xff08;時機&#xff09;做分解開。在單線 程應用中&#xff0c;目的與時機緊密耦…

【OpenCV 圖像處理 Python版】OpenCV 簡介及安裝

文章目錄 1.OpenCV 介紹1.1 OpenCV 的特點1.2 OpenCV 的主要模塊1.3 OpenCV 的應用場景 2.OpenCV-Python 庫3.OpenCV 安裝 1.OpenCV 介紹 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一個開源的計算機視覺和機器學習軟件庫。它由英特爾公司于1999年…

API的優勢及應用場景(淘寶API測試的詳細步驟)

一、API的優勢 API的出現為應用程序間的通信提供了一種新的方式&#xff0c;它有以下優勢&#xff1a; 1、降低開發難度 開發者可以通過API訪問其他應用程序的數據和功能&#xff0c;避免了重復開發&#xff0c;降低了開發難度。 2、提高開發效率 API提供了一種標準化的通…

Transformer 模型全解析:NLP領域的變革者與任務精粹

標題&#xff1a;Transformer 模型全解析&#xff1a;NLP領域的變革者與任務精粹 引言 Transformer 模型自問世以來&#xff0c;已成為自然語言處理&#xff08;NLP&#xff09;領域的一大突破&#xff0c;其基于自注意力機制的架構為各種語言任務帶來了革命性的進展。本文將…

使用AES,前端加密,后端解密,spring工具類,直接c就完事了

學習python的時候&#xff0c;看到很多會對參數進行加密&#xff0c;于是好奇心驅使下&#xff0c;讓我去了解了下AES加密如何在java中實現。 首先 npm install crypto-js 然后在你的方法中&#xff0c;給你們前端源碼看看&#xff0c;因為我用的ruoyi框架做的實驗&#xff…

Java中的消息隊列與事件總線設計

Java中的消息隊列與事件總線設計 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01;今天我們將探討Java中的消息隊列與事件總線設計&#xff0c;這兩者在現代分布式…

構建一個檢索增強生成(RAG)應用程序

:::tips 此文檔是LangChain官方教程的實踐總結&#xff1a;https://python.langchain.com/v0.2/docs/tutorials/rag/實踐前你需要準備&#xff1a;OPENAI_API_KEY Generator&#xff1a;根據檢索到的信息和用戶的查詢生成自然語言的回答。LANGCHAIN_API_KEY 密切監控和評估您的…

【自然語言處理系列】掌握NLP基礎:去停用詞、詞性標注與命名實體識別實戰教程

摘要&#xff1a;本系列教程專注于自然語言處理&#xff08;NLP&#xff09;中的基礎元素&#xff0c;包括去停用詞、詞性標注以及命名實體識別。這些步驟是文本預處理和分析不可或缺的組成部分。我們將通過具體的實例和技術演示&#xff0c;講解如何使用Python及其相關庫&…

網絡安全之Windows提權(上篇)(高級進階)

目錄 一&#xff0c;什么是提權&#xff1f; 二&#xff0c;提權的前提 三&#xff0c;如何提權&#xff1f; 1&#xff0c;第一步連接服務器 2&#xff0c;提升權限至iuser?編輯 3&#xff0c;利用補丁漏洞提權至最高級 四&#xff0c;總結 一&#xff0c;什么是提權&am…