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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

二叉树题目小合集

發布時間:2023/12/8 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二叉树题目小合集 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

94. 二叉樹的中序遍歷

給定一個二叉樹的根節點 root ,返回 它的 中序 遍歷 。
示例 1:
輸入:root = [1,null,2,3]
輸出:[1,3,2]
示例 2:
輸入:root = []
輸出:[]
示例 3:
輸入:root = [1]
輸出:[1]

遞歸非遞歸都是很統一的思路,要輸出父母結點就必須先輸出左孩子結點再輸出父母結點再輸出右孩子結點。每個結點都應該這樣操作。

首先是簡單的遞歸中序遍歷,大體思路記錄一下吧,先輸出左孩子,再輸出父節點,再輸出右孩子。輸出左孩子f也是先輸出左孩子的左孩子,再輸出這個f然后再輸出f的右孩子,顯然是個遞歸。就直接函數調用。
或者可以這樣理解

class Solution { public://存儲結果vector<int> result;void mid(TreeNode* root){//根不為空if(root){//遍歷左子樹mid(root->left);//輸出根節點(對于第一個要輸出的左節點,其實可以看成根節點,只不過是一個沒有左右子樹的根結點,希望可以幫助不太理解的理解下遞歸)result.push_back(root->val);//遍歷右子樹mid(root->right)}}vector<int> inorderTraversal(TreeNode* root) {mid(root);return result;} };

非遞歸的中序遍歷,要借用棧,其實遞歸本身就是用棧實現的,思路和上面類似,我要輸出父節點,就必須先輸出左孩子。要輸出這個左孩子,就必須輸出它的左孩子。那就需要把父節點的左孩子壓入棧,先處理左孩子的那個左孩子。后進先出,所以要用棧

class Solution { public:vector<int> inorderTraversal(TreeNode* root) {//建立棧存儲結點stack<TreeNode*> st;//存儲結果vector<int> result;//auto自動推斷類型,建立變量存儲rootauto q=root;//這里的q主要是針對根節點的進入,如果根結點為null不會進入//當棧內的元素彈完了,樹也就遍歷完了while(q||!st.empty()){//將左子樹全部壓入棧while(q){st.push(q);q=q->left;}//當沒有左子樹時,棧上的top點應該是最先輸出的,從棧內彈出它并把這個葉子的值放入result數組中auto node=st.top();st.pop();result.push_back(node->val);//處理剛才那個點的右子樹q=node->right;}return result;} };

101. 對稱二叉樹

給你一個二叉樹的根節點 root , 檢查它是否軸對稱。
示例 1:

輸入:root = [1,2,2,3,4,4,3]
輸出:true
提示:
樹中節點數目在范圍 [1, 1000] 內
-100 <= Node.val <= 100

首先考慮遞歸的思路:
對稱二叉樹上面的圖應該很容易了解了,兩個結點,一個結點的左子樹等于另一個結點的右子樹,另一個結點的右子樹又等于這個結點的左子樹。對每一個結點都應當是這樣判斷的,可以把從樹的根拆開,這樣就可以對兩棵樹進行比較了

class Solution { public:bool is(TreeNode* root1,TreeNode* root2){//當兩個結點都不存在時返回trueif(!root1&&!root2){return true;}//只有一個結點不存在時返回falseif(!root1||!root2){return false;}//比較兩個結點的值,并且遞歸return root1->val==root2->val&&is(root1->left,root2->right)&&is(root1->right,root2->left);}bool isSymmetric(TreeNode* root) {return is(root,root);} };

非遞歸的思路:
還是從根結點拆開為兩個樹,因為我們從頭開始判斷,遇到不相等的就結束,所以借用隊列這一工具,將a樹的左節點與b樹的右節點比較,將a樹的右節點再與b樹的左節點比較。同時每次結點比較完畢,就應該把他對應的左右結點壓入隊列,以免丟失剩下的結點。

class Solution { public:bool isSymmetric(TreeNode* root) {queue<TreeNode*> qu;//拆為兩棵樹qu.push(root);qu.push(root);while(!qu.empty()){//從頭連續取出兩個結點auto a=qu.front();qu.pop();auto b=qu.front();qu.pop();//均為空也是相等的,但是沒有左右子樹可以插入if(!a&&!b)continue;//一方為空或者值不相等則返回不相等if(!a||!b) return false;if(a->val!=b->val) return false;//左右,右左插入(每次插入的兩個值應該時相等的)qu.push(a->left);qu.push(b->right);qu.push(a->right);qu.push(b->left);}return true;} };

100. 相同的樹

給你兩棵二叉樹的根節點 p 和 q ,編寫一個函數來檢驗這兩棵樹是否相同。
如果兩個樹在結構上相同,并且節點具有相同的值,則認為它們是相同的。
示例 1:
輸入:p = [1,2,3], q = [1,2,3]
輸出:true
示例 2:
輸入:p = [1,2], q = [1,null,2]
輸出:false

遞歸思路:
對于每個結點,如果都為空則相等,其中一個為空則不相等,(這兩個必須先處理,不然處理數可能存在空指針,會報錯)數不同不相等,相同的話再判斷它們的左孩子和右孩子。這樣一想,循環體就有了

class Solution { public:bool isSameTree(TreeNode* p, TreeNode* q) {//先判斷節點的存在情況if(!p&&!q){return true;}if(!p||!q){return false;}if(p->val!=q->val){return false;}//判斷值和左右子樹return p->val==q->val&&isSameTree(p->left,q->left)&&isSameTree(p->right,q->right); } };

非遞歸思路
因為一遇到不同的就終止,所以使用隊列,其實這個題和上題的思路很像,只不過不是左對右,右對左壓入了,而是左對左,右對右的壓入比較

class Solution { public:bool isSameTree(TreeNode* p, TreeNode* q) {queue<TreeNode*> qu;qu.push(p);qu.push(q);while(!qu.empty()){//連續取兩個節點auto a=qu.front();qu.pop();auto b=qu.front();qu.pop();//均不存在是相等的,但是無插入操作if(!a&&!b)continue;//單個存在或值不相等,返回不相等if(!a||!b)return false;if(a->val!=b->val)return false;//連續插入左左,右右qu.push(a->left);qu.push(b->left);qu.push(a->right);qu.push(b->right);}return true;} };

98. 驗證二叉搜索樹

給你一個二叉樹的根節點 root ,判斷其是否是一個有效的二叉搜索樹。
有效 二叉搜索樹定義如下:
節點的左子樹只包含 小于 當前節點的數。
節點的右子樹只包含 大于 當前節點的數。
所有左子樹和右子樹自身必須也是二叉搜索樹。
示例 1:

輸入:root = [2,1,3]
輸出:true

思路:
遞歸思路
我們先把注意力集中在單個節點的判斷上,即它的左孩子應該小于父節點,右孩子應該大于父節點。事情的特殊點在于父節點R左孩子R1的右孩子r1和右孩子R2的左孩子r2。r1應該在大于R1的同時小于R,r2應該在小于R2的同時大于R。因此在處理時應該把R的值傳下來用作判斷R1和R2的孩子的限制。給左子樹則作為上界,右子樹作為下界。可以保證左右兩邊的子樹合理。

class Solution { public:bool is(TreeNode* root,long long int upper,long long int lower){//節點為空和值不相等的狀況if(!root){return true;}if(root->val>=upper||root->val<=lower){return false;}//繼續比對下一層return is(root->left,root->val,lower)&&is(root->right,upper,root->val);}bool isValidBST(TreeNode* root) {//upper和lower初值分別設最大和最小,因為范圍在正負2的31次方return is(root,LONG_MAX,LONG_MIN);} };

中序遍歷排列
對二叉搜索樹進行中序遍歷,得到的結果必然是一個遞增序列。例如上圖,得到的中序遍歷應當是2345678。因此中序遍歷二叉樹,只要發現不是遞增的點就不是二叉搜索樹

寫完之后看了官方的版本,我這個版本其實不太好,其實不需要使用隊列來存儲節點的值,直接保存上一個節點的值進行比較就好了

class Solution { public:bool isValidBST(TreeNode* root) {//中序遍歷的工具棧stack<TreeNode*> qu;//借由存儲節點的值queue<int> adjust;auto q=root;//第一次不需要比較,執行一次adjust.pop()之后才開始比較bool key =false;while(q||!qu.empty()){while(q){qu.push(q);q=q->left;}auto node=qu.top();qu.pop();adjust.push(node->val);if(key){//彈出隊列的第一個值,和此時隊列的頭比較auto a=adjust.front();adjust.pop();if(a>=adjust.front()){return false;}}q=node->right;key=true;}return true;} };

上一下官方的代碼做參考

class Solution { public:bool isValidBST(TreeNode* root) {stack<TreeNode*> stack;long long inorder = (long long)INT_MIN - 1;while (!stack.empty() || root != nullptr) {while (root != nullptr) {stack.push(root);root = root -> left;}root = stack.top();stack.pop();// 如果中序遍歷得到的節點的值小于等于前一個 inorder,說明不是二叉搜索樹if (root -> val <= inorder) {return false;}inorder = root -> val;root = root -> right;}return true;} };作者:LeetCode-Solution 鏈接:https://leetcode-cn.com/problems/validate-binary-search-tree/solution/yan-zheng-er-cha-sou-suo-shu-by-leetcode-solution/ 來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

劍指 Offer 33. 二叉搜索樹的后序遍歷序列

輸入一個整數數組,判斷該數組是不是某二叉搜索樹的后序遍歷結果。如果是則返回 true,否則返回 false。假設輸入的數組的任意兩個數字都互不相同。
參考以下這顆二叉搜索樹:
5
/
2 6
/
1 3
示例 1:
輸入: [1,6,3,2,5]
輸出: false
示例 2:
輸入: [1,3,2,6,5]
輸出: true

遞歸思路
二叉搜索樹上方已經提到過,左子樹全部小于根,右子樹全部大于根。而后續遍歷最末尾一個元素一定是根。因此將數組和根比較。前面小于根的元素一定是左子樹,那么除根之外的元素一定是右子樹,我們只用判斷剩下的這些元素是不是全部大于根。若不是則返回false,是則對左子樹和右子樹再進行上面的算法比較,直到全部比較完為止

才發現我的記憶出了錯亂,之前判斷函數全用的adjust,應該用judge才對。而且這次代碼中名字又寫錯了。。。第一個手快打錯后面提示就跟著錯

class Solution { public:bool judeg(vector<int>& postorder,int start,int end){//表明比較完了if(start>=end){return true;}//記錄根的值,記不記其實無所謂int key=postorder[end];//遞歸還要用到start,所以要建變量int i=start;//這都是左子樹。循環結束時i在左子樹后一位while(postorder[i]<key){i++;}//這都是右子樹,同上int m=i;while(postorder[m]>key){m++;}//中途右不大于根的,說明不是二叉搜索樹if(m!=end){return false;}//繼續判斷上方的左右子樹是不是二叉搜索樹return m==end&&judeg(postorder,start,i-1)&&judeg(postorder,i,end-1);}bool verifyPostorder(vector<int>& postorder) {return judeg(postorder,0,postorder.size()-1);} };

單調棧
大體的思路就時倒歷后序遍歷,(后序遍歷左右根,倒歷就是根右左)借由棧。初始設置根為無窮大,后序遍歷的時候,根一定出現在左子樹的后面,因此倒敘時,根應該比左子樹先出現,把根壓入棧中,在遇到左子樹之前,出現的一定是遞增序列(如果右子樹為右子樹單鏈表則會出現遞增序列)。因此把棧彈到最后一個大于左子樹結點的一定是左子樹的根。這個根的右子樹一定都處理完了,接下來的就都是它的左子樹或者這個根的父節點左子樹,這些左子樹都應當比根小,將這些都順序處理掉,直到遇到一個新的遞增序列,這個遞增序列一定是一個根的右子樹,再次找到這個右子樹所連的根…

感覺其實也講不太清楚,弄一個案例幫助理解吧

畫橫線的都是左子樹,可以看出所有的左子樹都是小于根的,一開始令根等于無窮大,目的就是把最開始那一段右子樹給拆掉

class Solution { public:bool verifyPostorder(vector<int>& postorder) {stack<int> st;int root=INT_MAX;;for(int i=postorder.size()-1;i>=0;i--){if(postorder[i]>root){return false;}while(!st.empty()&&postorder[i]<st.top()){root=st.top();st.pop();}st.push(postorder[i]);}return true;} };

總結

以上是生活随笔為你收集整理的二叉树题目小合集的全部內容,希望文章能夠幫你解決所遇到的問題。

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