Given a tree, rearrange the tree in in-order so that the leftmost node in the tree is now the root of the tree, and every node has no left child and only 1 right child.html
Example 1: Input: [5,3,6,2,4,null,8,1,null,null,null,7,9] 5 / \ 3 6 / \ \ 2 4 8 / / \ 1 7 9 Output: [1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9] 1 \ 2 \ 3 \ 4 \ 5 \ 6 \ 7 \ 8 \ 9
Note:node
這道題給了一棵二叉樹,讓咱們對其進行重排序,使得最左結點變爲根結點,並且整個樹不能有左子結點,如題目中的例子所示,排序後的結果是一條向右下方延伸的直線。若是咱們仔細觀察題目中的例子,能夠發現遍歷順序實際上是 左->根->右,就是中序遍歷的順序,雖然題目中沒說是二叉搜索樹,但這並不影響咱們進行中序遍歷。咱們先從最簡單的例子開始分析,當 root 爲空時,直接返回空,當 root 沒有左右子結點時,也是直接返回 root。當 root 只有一個左子結點時,咱們此時要把其左子結點變爲根結點,將原來的根結點變成其原來的左子結點的右子結點。可是若是 root 只有一個右子結點,仍是保持原來的順序不變,而若 root 同時具備左右子結點的話,仍是要將左子結點變爲根結點,而後把以前的根結點連到右子結點上,以前的右子結點還連在以前的根結點上,這個不用改變。咱們能夠發現,最麻煩的就是左子結點了,須要和其根結點交換位置,因此對於每一個結點,咱們須要知道其父結點的位置,那麼就在遞歸函數的參數中傳入一個 pre 結點,再對左右子結點調用遞歸函數時,都將其下一個要鏈接的結點傳入,這個 pre 結點多是當前結點或者當前結點的父結點。git
在遞歸函數中,首先判空,若當前結點爲空的話,直接返回 pre 結點,由於到空結點的時候,說明已經遍歷到葉結點的下方了,那麼 pre 就是這個葉結點了。因爲是中序遍歷,因此要先對左子結點調用遞歸函數,將返回值保存到一個新的結點 res 中,表示的意義是此時 node 的左子樹已經所有捋直了,並且根結點就是 res,並且 node 結點自己也被連到了捋直後的左子樹下,即此時左子結點和根結點已經完成了交換位子,固然要斷開原來的鏈接,因此將 node->left 賦值爲 nullptr。而後再對 node 的右子結點調用遞歸函數,注意此時的 pre 不能傳入 node 自己,而是要傳 node 結點的 pre 結點,這是由於右子結點後面要鏈接的是 node 的父結點,好比兌入下面這例子:github
4 / 2 / \ 1 3
當運行到結點3的時候,pre 應該帶入的是結點4,這樣就能夠把結點4連到結點3的右下方,從而正確的捋直,參見代碼以下:函數
解法一:code
class Solution { public: TreeNode* increasingBST(TreeNode* root) { return helper(root, nullptr); } TreeNode* helper(TreeNode* node, TreeNode* pre) { if (!node) return pre; TreeNode* res = helper(node->left, node); node->left = nullptr; node->right = helper(node->right, pre); return res; } };
咱們也能夠採用中序遍歷的迭代形式,使用棧來輔助。因爲根結點可能會產生變化,因此咱們須要一個 dummy 結點,還須要一個 pre 結點。在 while 循環中,先找到最左結點,把路徑上的全部結點都壓入棧,而後取出棧頂元素,將其連到 pre 的右子結點上,並將 pre 更新爲其右子結點,而後斷開棧頂元素的左子結點鏈接,並將其移動到右子結點上,並繼續循環,最終返回 dummy 的右子結點便可,參見代碼以下:htm
解法二:blog
class Solution { public: TreeNode* increasingBST(TreeNode* root) { TreeNode *dummy = new TreeNode(-1), *pre = dummy; stack<TreeNode*> st; while (root || !st.empty()) { while (root) { st.push(root); root = root->left; } root = st.top(); st.pop(); pre->right = root; pre = pre->right; root->left = nullptr; root = root->right; } return dummy->right; } };
Github 同步地址:排序
https://github.com/grandyang/leetcode/issues/897遞歸
參考資料:
https://leetcode.com/problems/increasing-order-search-tree/
https://leetcode.com/problems/increasing-order-search-tree/discuss/251290/C%2B%2B-short-iterative