LeetCode:Recover Binary Search Tree Binary Tree Inorder Traversal

其餘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. 首先找到第一個錯誤的數first,即第一個比它後綴要大的數
  2. 而後要找到第一個錯誤的數應該放置的位置(這就是第二個錯誤的數),即要找到第一個比first大的數的前驅,這個前驅就是第一個錯誤的數應該放的位置,也就是第二個錯誤的數。(注意一個特殊狀況{0,1},first爲1,沒有找到比first大的數,這是second就是最後一個數0)

算法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 };
View Code

 

算法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

相關文章
相關標籤/搜索