其餘LeetCode題目歡迎訪問:LeetCode結題報告索引css
題目連接html
Two elements of a binary search tree (BST) are swapped by mistake.算法
Recover the tree without changing its structure.app
Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?ide
分析:首先咱們最直觀的的想法是中序遍歷獲得中序序列,平衡二叉樹的中序序列是非遞減有序的。那麼問題就轉化成了在非遞減有序序列中交換了兩個數的位置,找出這兩個數並恢復有序序列,這個問題能夠經過遍歷一遍有序序列分下面2步完成:post
算法1:咱們能夠用遞歸中序遍歷(或者使用棧的非遞歸中序遍歷)來實現,可是這樣空間複雜度都是O(n)。下面代碼是遞歸中序遍歷,能夠經過ojurl
1 /** 2 * Definition for binary tree 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 void recoverTree(TreeNode *root) { 13 // IMPORTANT: Please reset any member data you declared, as 14 // the same Solution instance will be reused for each test case. 15 TreeNode *pre = NULL, *first = NULL, *second = NULL; 16 inorder(root, pre, first, second); 17 if(first != NULL) 18 { 19 if(second == NULL)second = pre;//樹{0,1}就可能出現這種狀況 20 int tmp = first->val; 21 first->val = second->val; 22 second->val = tmp; 23 } 24 } 25 //pre是中序序列中當前節點的前驅,first、second分別是要找的兩個亂序節點 26 void inorder(TreeNode *root, TreeNode* &pre, TreeNode* &first, TreeNode* &second) 27 { 28 if(root == NULL)return; 29 if(root->left)inorder(root->left, pre, first, second); 30 if(pre != NULL) 31 { 32 if(first == NULL && root->val < pre->val) 33 first = pre; 34 else if(first && root->val > first->val) 35 {second = pre; return;}//兩個錯誤位置都找到就退出 36 } 37 pre = root; 38 if(root->right)inorder(root->right, pre, first, second); 39 } 40 };
算法2:爲了知足O(1)空間複雜度,咱們就要使用非遞歸且不使用棧的中序遍歷算法,在leetcode另外一個題目Binary Tree Inorder Traversal中,咱們提到了Morris Traversal中序遍歷算法,它既沒有遞歸,也沒有使用棧,而是用了線索二叉樹的思想,用閒置的右節點指向中序序列中該節點的後綴,遍歷後再恢復樹的原始指針。其主要算法步驟以下:spa
重複如下一、2直到當前節點爲空。 本文地址指針
1. 若是當前節點的左孩子爲空,則輸出當前節點並將其右孩子做爲當前節點。rest
2. 若是當前節點的左孩子不爲空,在當前節點的左子樹中找到當前節點在中序遍歷下的前驅節點(即當前節點的左子樹的最右節點)。
a) 若是前驅節點的右孩子爲空,將它的右孩子設置爲當前節點(利用這個空的右孩子指向它的後綴)。當前節點更新爲當前節點的左孩子。
b) 若是前驅節點的右孩子爲當前節點,將它的右孩子從新設爲空(恢復樹的形狀)。輸出當前節點。當前節點更新爲當前節點的右孩子。
只要在上述遍歷算法上加幾行代碼(紅色代碼)判斷元素是否有序的代碼就能夠找出亂序的兩個節點(一樣也是利用上面的思想分別找到第一第二個亂序數)
須要注意的是:不能像上面的算法1那樣,找到兩個錯誤的數就退出循環。由於Morris Traversal算法破壞了原來的樹的結構,須要整個循環都運行完成恢復樹的結構。否則的話,就如本文第一條評論中那樣,oj會出現TLE錯誤
1 /** 2 * Definition for binary tree 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 void recoverTree(TreeNode *root) { 13 // IMPORTANT: Please reset any member data you declared, as 14 // the same Solution instance will be reused for each test case. 15 //first,second 分別指向兩個錯誤的節點,parent保存中序訪問中當前節點的前驅 16 TreeNode *first = NULL, *second = NULL, *parent = NULL; 17 TreeNode *current = root, *pre = NULL; 18 while(current != NULL) 19 { 20 if(current->left == NULL) 21 { 22 if(parent != NULL) 23 { 24 if(first == NULL && current->val < parent->val) 25 first = parent; 26 else if(first && !second && current->val > first->val) 27 second = parent; 28 } 29 parent = current; 30 current = current->right; 31 } 32 else 33 { 34 /* Find the inorder predecessor of current */ 35 pre = current->left; 36 while(pre->right != NULL && pre->right != current) 37 pre = pre->right; 38 39 if(pre->right == NULL) 40 { /* Make current as right child of its inorder predecessor */ 41 pre->right = current; 42 current = current->left; 43 } 44 else 45 { 46 /* Revert the changes made in if part to restore the original 47 tree i.e., fix the right child of predecssor */ 48 //這裏parent確定不等於NULL 49 if(first == NULL && current->val < parent->val) 50 first = parent; 51 else if(first && !second && current->val > first->val) 52 second = parent; 53 parent = current; 54 55 pre->right = NULL; 56 current = current->right; 57 } 58 } 59 } 60 if(first != NULL) 61 { 62 if(second == NULL)second = parent;//樹{0,1}就可能出現這種狀況 63 int tmp = first->val; 64 first->val = second->val; 65 second->val = tmp; 66 } 67 } 68 };
【版權聲明】轉載請註明出處:http://www.cnblogs.com/TenosDoIt/p/3445682.html