日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

消除左递归实验代码_「leetcode」108. 构造二叉搜索树【递归】【迭代】详解!

發布時間:2023/11/27 生活经验 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 消除左递归实验代码_「leetcode」108. 构造二叉搜索树【递归】【迭代】详解! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
構造二叉搜索樹,一不小心就平衡了
?

108.將有序數組轉換為二叉搜索樹

將一個按照升序排列的有序數組,轉換為一棵高度平衡二叉搜索樹。

本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。

示例:

思路

題目中說要轉換為一棵高度平衡二叉搜索樹。這和轉換為一棵普通二叉搜索樹有什么差別呢?

其實這里不用強調平衡二叉搜索樹,數組構造二叉樹,構成平衡樹是自然而然的事情,因為大家默認都是從數組中間位置取值作為節點元素,一般不會隨機取,「所以想構成不平衡的二叉樹是自找麻煩」

在二叉樹:構造二叉樹登場!和二叉樹:構造一棵最大的二叉樹中其實已經講過了,如果根據數組構造一顆二叉樹。

「本質就是尋找分割點,分割點作為當前節點,然后遞歸左區間和右區間」

本題其實要比二叉樹:構造二叉樹登場! 和 二叉樹:構造一棵最大的二叉樹簡單一些,因為有序數組構造二叉搜索樹,尋找分割點就比較容易了。

分割點就是數組中間位置的節點。

那么為問題來了,如果數組長度為偶數,中間節點有兩個,取哪一個?

取哪一個都可以,只不過構成了不同的平衡二叉搜索樹。

例如:輸入:[-10,-3,0,5,9]

如下兩棵樹,都是這個數組的平衡二叉搜索樹:

如果要分割的數組長度為偶數的時候,中間元素為兩個,是取左邊元素 就是樹1,取右邊元素就是樹2。

「這也是題目中強調答案不是唯一的原因。理解這一點,這道題目算是理解到位了」

遞歸

遞歸三部曲:

  • 確定遞歸函數返回值及其參數

刪除二叉樹節點,增加二叉樹節點,都是用遞歸函數的返回值來完成,這樣是比較方便的。

相信大家如果仔細看了二叉樹:搜索樹中的插入操作和二叉樹:搜索樹中的刪除操作,一定會對遞歸函數返回值的作用深有感觸。

那么本題要構造二叉樹,依然用遞歸函數的返回值來構造中節點的左右孩子。

再來看參數,首先是傳入數組,然后就是左下表left和右下表right,我們在二叉樹:構造二叉樹登場!中提過,在構造二叉樹的時候盡量不要重新定義左右區間數組,而是用下表來操作原數組。

所以代碼如下:

// 左閉右閉區間[left, right]
TreeNode* traversal(vector<int>& nums, int left, int right) 

這里注意,「我這里定義的是左閉右閉區間,在不斷分割的過程中,也會堅持左閉右閉的區間,這又涉及到我們講過的循環不變量」

在二叉樹:構造二叉樹登場!,35.搜索插入位置 和59.螺旋矩陣II都詳細講過循環不變量。

  • 確定遞歸終止條件

這里定義的是左閉右閉的區間,所以當區間 left > right的時候,就是空節點了。

代碼如下:

if (left > right) return nullptr;
  • 確定單層遞歸的邏輯

首先取數組中間元素的位置,不難寫出int mid = (left + right) / 2;「這么寫其實有一個問題,就是數值越界,例如left和right都是最大int,這么操作就越界了,在二分法中尤其需要注意!」

所以可以這么寫:int mid = left + ((right - left) / 2);

但本題leetcode的測試數據并不會越界,所以怎么寫都可以。但需要有這個意識!

取了中間位置,就開始以中間位置的元素構造節點,代碼:TreeNode* root = new TreeNode(nums[mid]);

接著劃分區間,root的左孩子接住下一層左區間的構造節點,右孩子接住下一層右區間構造的節點。

最后返回root節點,單層遞歸整體代碼如下:

int mid = left + ((right - left) / 2); 
TreeNode* root = new TreeNode(nums[mid]);
root->left = traversal(nums, left, mid - 1);
root->right = traversal(nums, mid + 1, right);
return root;

這里int mid = left + ((right - left) / 2);的寫法相當于是如果數組長度為偶數,中間位置有兩個元素,取靠左邊的。

  • 遞歸整體代碼如下:
class Solution {
private:TreeNode* traversal(vector<int>& nums, int left, int right) {if (left > right) return nullptr;int mid = left + ((right - left) / 2); TreeNode* root = new TreeNode(nums[mid]);root->left = traversal(nums, left, mid - 1);root->right = traversal(nums, mid + 1, right);return root;}
public:TreeNode* sortedArrayToBST(vector<int>& nums) {TreeNode* root = traversal(nums, 0, nums.size() - 1);return root;}
};

「注意:在調用traversal的時候為什么傳入的left和right為什么是0和nums.size() - 1,因為定義的區間為左閉右閉」

迭代法

迭代法可以通過三個隊列來模擬,一個隊列放遍歷的節點,一個隊列放左區間下表,一個隊列放右區間下表。

模擬的就是不斷分割的過程,C++代碼如下:(我已經詳細注釋)

class Solution {
public:TreeNode* sortedArrayToBST(vector<int>& nums) {if (nums.size() == 0) return nullptr;TreeNode* root = new TreeNode(0);   // 初始根節點queue<TreeNode*> nodeQue;           // 放遍歷的節點queue<int> leftQue;                 // 保存左區間下表queue<int> rightQue;                // 保存右區間下表nodeQue.push(root);                 // 根節點入隊列leftQue.push(0);                    // 0為左區間下表初始位置rightQue.push(nums.size() - 1);     // nums.size() - 1為右區間下表初始位置while (!nodeQue.empty()) {TreeNode* curNode = nodeQue.front();nodeQue.pop();int left = leftQue.front(); leftQue.pop();int right = rightQue.front(); rightQue.pop();int mid = left + ((right - left) / 2);curNode->val = nums[mid];       // 將mid對應的元素給中間節點if (left <= mid - 1) {          // 處理左區間curNode->left = new TreeNode(0);nodeQue.push(curNode->left);leftQue.push(left);rightQue.push(mid - 1);}if (right >= mid + 1) {         // 處理右區間curNode->right = new TreeNode(0);nodeQue.push(curNode->right);leftQue.push(mid + 1);rightQue.push(right);}}return root;}
};

總結

「在二叉樹:構造二叉樹登場! 二叉樹:構造一棵最大的二叉樹之后,我們順理成章的應該構造一下二叉搜索樹了,一不小心還是一棵平衡二叉搜索樹」

其實思路也是一樣的,不斷中間分割,然后遞歸處理左區間,右區間,也可以說是分治。

此時相信大家應該對通過遞歸函數的返回值來增刪二叉樹很熟悉了,這也是常規操作。

在定義區間的過程中我們又一次強調了循環不變量的重要性。

最后依然給出迭代的方法,其實就是模擬取中間元素,然后不斷分割去構造二叉樹的過程。

「就醬,如果對你有幫助的話,也轉發給身邊需要的同學吧!」

本文:

https://github.com/youngyangyang04/leetcode-master?github.com

已經收錄,里面還有leetcode刷題攻略、各個類型經典題目刷題順序、思維導圖,可以fork到自己倉庫,有空看一看一定會有所收獲,如果對你有幫助也給一個star支持一下吧!

我的B站(里面有我講解的算法視頻已經編程相關知識):

嗶哩嗶哩 ( ゜- ゜)つロ 乾杯~ Bilibili?space.bilibili.com

我是程序員Carl,哈工大師兄,先后在騰訊和百度從事技術研發多年,利用工作之余重刷leetcode,更多精彩算法文章盡在公眾號:代碼隨想錄,關注后,回復「Java」「C++」「python」「簡歷模板」等等,有我整理多年的學習資料,可以加我微信,備注「個人簡介」+「組隊刷題」,拉你進入刷題群,每天一道經典題目分析,我選的每一道題目都不是孤立的,而是由淺入深一脈相承的,如果跟住節奏每篇連續著看,定會融會貫通。

總結

以上是生活随笔為你收集整理的消除左递归实验代码_「leetcode」108. 构造二叉搜索树【递归】【迭代】详解!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。