二叉树题目小合集
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> 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
首先考慮遞歸的思路:
對稱二叉樹上面的圖應該很容易了解了,兩個結點,一個結點的左子樹等于另一個結點的右子樹,另一個結點的右子樹又等于這個結點的左子樹。對每一個結點都應當是這樣判斷的,可以把從樹的根拆開,這樣就可以對兩棵樹進行比較了
非遞歸的思路:
還是從根結點拆開為兩個樹,因為我們從頭開始判斷,遇到不相等的就結束,所以借用隊列這一工具,將a樹的左節點與b樹的右節點比較,將a樹的右節點再與b樹的左節點比較。同時每次結點比較完畢,就應該把他對應的左右結點壓入隊列,以免丟失剩下的結點。
100. 相同的樹
給你兩棵二叉樹的根節點 p 和 q ,編寫一個函數來檢驗這兩棵樹是否相同。
如果兩個樹在結構上相同,并且節點具有相同的值,則認為它們是相同的。
示例 1:
輸入:p = [1,2,3], q = [1,2,3]
輸出:true
示例 2:
輸入:p = [1,2], q = [1,null,2]
輸出:false
遞歸思路:
對于每個結點,如果都為空則相等,其中一個為空則不相等,(這兩個必須先處理,不然處理數可能存在空指針,會報錯)數不同不相等,相同的話再判斷它們的左孩子和右孩子。這樣一想,循環體就有了
非遞歸思路
因為一遇到不同的就終止,所以使用隊列,其實這個題和上題的思路很像,只不過不是左對右,右對左壓入了,而是左對左,右對右的壓入比較
98. 驗證二叉搜索樹
給你一個二叉樹的根節點 root ,判斷其是否是一個有效的二叉搜索樹。
有效 二叉搜索樹定義如下:
節點的左子樹只包含 小于 當前節點的數。
節點的右子樹只包含 大于 當前節點的數。
所有左子樹和右子樹自身必須也是二叉搜索樹。
示例 1:
輸入:root = [2,1,3]
輸出:true
思路:
遞歸思路
我們先把注意力集中在單個節點的判斷上,即它的左孩子應該小于父節點,右孩子應該大于父節點。事情的特殊點在于父節點R左孩子R1的右孩子r1和右孩子R2的左孩子r2。r1應該在大于R1的同時小于R,r2應該在小于R2的同時大于R。因此在處理時應該把R的值傳下來用作判斷R1和R2的孩子的限制。給左子樹則作為上界,右子樹作為下界。可以保證左右兩邊的子樹合理。
中序遍歷排列
對二叉搜索樹進行中序遍歷,得到的結果必然是一個遞增序列。例如上圖,得到的中序遍歷應當是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);} };單調棧
大體的思路就時倒歷后序遍歷,(后序遍歷左右根,倒歷就是根右左)借由棧。初始設置根為無窮大,后序遍歷的時候,根一定出現在左子樹的后面,因此倒敘時,根應該比左子樹先出現,把根壓入棧中,在遇到左子樹之前,出現的一定是遞增序列(如果右子樹為右子樹單鏈表則會出現遞增序列)。因此把棧彈到最后一個大于左子樹結點的一定是左子樹的根。這個根的右子樹一定都處理完了,接下來的就都是它的左子樹或者這個根的父節點左子樹,這些左子樹都應當比根小,將這些都順序處理掉,直到遇到一個新的遞增序列,這個遞增序列一定是一個根的右子樹,再次找到這個右子樹所連的根…
感覺其實也講不太清楚,弄一個案例幫助理解吧
畫橫線的都是左子樹,可以看出所有的左子樹都是小于根的,一開始令根等于無窮大,目的就是把最開始那一段右子樹給拆掉
總結
- 上一篇: 中职学生学业水平计算机考试试题,中职学业
- 下一篇: 啥子是JSON转化