-
Notifications
You must be signed in to change notification settings - Fork 119
/
Copy path99. Recover Binary Search Tree.cpp
150 lines (136 loc) · 5.07 KB
/
99. Recover Binary Search Tree.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//Runtime: 56 ms, faster than 20.38% of C++ online submissions for Recover Binary Search Tree.
//Memory Usage: 55.2 MB, less than 5.06% of C++ online submissions for Recover Binary Search Tree.
//time: O(N), space: O(N)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<TreeNode*> nodes;
vector<int> vals;
void inorder(TreeNode* node){
if(!node) return;
inorder(node->left);
nodes.push_back(node);
vals.push_back(node->val);
inorder(node->right);
}
void inorder_revise(TreeNode* node, int& order, vector<int>& indices_to_revise, vector<int>& vals_to_revise){
if(!node) return;
inorder_revise(node->left, order, indices_to_revise, vals_to_revise);
auto it = find(indices_to_revise.begin(), indices_to_revise.end(), order);
if(it != indices_to_revise.end()){
// cout << "revise " << node->val << " to " << vals_to_revise[it-indices_to_revise.begin()] << endl;
node->val = vals_to_revise[it-indices_to_revise.begin()];
}
++order;
inorder_revise(node->right, order, indices_to_revise, vals_to_revise);
}
void recoverTree(TreeNode* root) {
inorder(root);
//the values in right order
sort(vals.begin(), vals.end());
vector<int> indices_to_revise;
vector<int> vals_to_revise;
for(int i = 0; i < nodes.size(); ++i){
//the node's value isn't the value it should be
if(nodes[i]->val != vals[i]){
indices_to_revise.push_back(i);
vals_to_revise.push_back(vals[i]);
}
}
int order = 0;
inorder_revise(root, order, indices_to_revise, vals_to_revise);
}
};
//Morris Traversal, threaded binary tree
//https://leetcode.com/problems/recover-binary-search-tree/discuss/32559/Detail-Explain-about-How-Morris-Traversal-Finds-two-Incorrect-Pointer
//Runtime: 48 ms, faster than 33.92% of C++ online submissions for Recover Binary Search Tree.
//Memory Usage: 53.7 MB, less than 33.72% of C++ online submissions for Recover Binary Search Tree.
//time: O(N), space: O(1)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode *cur, *prev;
TreeNode *first, *second;
void doWork(){
//do work related to this problem
if(prev != nullptr && prev->val > cur->val){
if(first == nullptr){
first = prev;
// cout << "first: " << prev->val << endl;
}
/*
also set second when first == nullptr,
this is so deal with the case that
first and second may be consecutive
*/
second = cur;
// cout << "second: " << cur->val << endl;
}
//maintain the "prev" pointer
prev = cur;
};
void recoverTree(TreeNode* root) {
cur = root;
prev = nullptr;
first = second = nullptr;
//the framework is Morris traversal
while(cur){
if(cur->left){
//find its predecessor in its left subtree
TreeNode* pred = cur->left;
while(pred->right != nullptr && pred->right != cur){
pred = pred->right;
}
if(pred->right == nullptr){
/*
connect the predecessor's right to cur,
so we can come back to cur later
*/
pred->right = cur;
/*
now that it is ensured that we can go back to cur later,
we can go to its left subtree safely
*/
cur = cur->left;
}else{
//here pred->right == cur
doWork();
// cout << cur->val << endl;
pred->right = nullptr;
/*
we have visit cur's left subtree and cur itself,
so go to its right subtree
*/
cur = cur->right;
}
}else{
doWork();
// cout << cur->val << endl;
cur = cur->right;
}
}
if(first != nullptr && second != nullptr){
swap(first->val, second->val);
}
}
};