- Inorder Predecessor in BST
中文English
Given a binary search tree and a node in it, find the in-order predecessor of that node in the BST.
Example
Example1
Input: root = {2,1,3}, p = 1
Output: null
Example2
Input: root = {2,1}, p = 2
Output: 1
Notice
If the given node has no in-order predecessor in the tree, return null
解法1:DFS。Inorder遍历,记下predessor节点。时间复杂度O(n)。
代码如下:
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: the given BST
* @param p: the given node
* @return: the in-order predecessor of the given node in the BST
*/
TreeNode * inorderPredecessor(TreeNode * root, TreeNode * p) {
if (!root) return NULL;
lastVisted = NULL; predecessorNode = NULL;
inOrderTraversal(root, p);
return predecessorNode;
}
private:
TreeNode * lastVisted;
TreeNode * predecessorNode;
void inOrderTraversal(TreeNode * root, TreeNode * p) {
if (!root || predecessorNode) return;
inOrderTraversal(root->left, p);
if (root == p) {
predecessorNode = lastVisted;
} else {
lastVisted = root;
}
inOrderTraversal(root->right, p);
}
};
注意:这题直接用一个如下的递归函数不对。因为NULL的情形也返回了。
TreeNode * inorderPredecessor(TreeNode * root, TreeNode * p) {
if (!root) return NULL;
inorderPredecessor(root->left, p);
if (root == p) {
return lastVisted;
} else {
lastVisted = root;
}
inorderPredecessor(root->right, p);
}
二刷:不如解法2好。
class Solution {
public:
/**
* @param root: the given BST
* @param p: the given node
* @return: the in-order predecessor of the given node in the BST
*/
TreeNode * inorderPredecessor(TreeNode * root, TreeNode * p) {
if (!root || !p) return NULL;
inorderTraversal(root, p);
return pre;
}
private:
TreeNode *pre = NULL;
bool found = false;
void inorderTraversal(TreeNode *root, TreeNode *p) {
if (!root || found) return;
if (root->left) inorderTraversal(root->left, p);
if (root == p) {
found = true;
return;
}
if (!found) pre = root;
if (root->right) inorderTraversal(root->right, p);
}
};
解法2:类似Binary Search。这里其实不需要遍历,用binary search就可以了,时间复杂度O(logn)。参考的网上的算法。我觉得这个算法非常好。
注意:
- p永远不变。
- 当p->val < root->val时,很明显,p的predessor是在左子树,所以root=root->left,进入下一轮循环。
当p->val == root->val时,其predessor也是在左子树,root=root->left,进入下一轮循环。注意当root == NULL时,就可以返回predessor。
当p->val > root->val时,其predessor可能是root,也可能在右子树,故将root=root->right,进入下一轮循环。 - 难点是p->val > root->val时的处理,我们必须不断更新root。
注意if语句
if (!pred || root->val > pred->val)
这里!pred是第一次遇到p->val > root->val的情况,此时pred=root第一次赋值。
root->val > pred->val是后面因为有了更合适的root,故更新pred。因为这里新的root->val比p->val小,又比之前的predessor->val大,故这个新root更适合做新的predessor。 - 举例如下
input = {20, 10, 40, 35, #}, 35
root = 20, p = 35, pred = NULL
root = 40, p = 35, pred = 20 //pred第一次赋值
root = 35, p = 35, pred = 20 //新root=35,但p->val==root->val,故不会进入else分支。
root = NULL return
总结一下:root一直在变,pred也在变,pred就是仅次于root的那个元素。注意这里是O(logn),没有用到中序遍历。但是pred就相当于root的中序遍历的前驱,因为它是仅次于root的那个元素。
代码如下:
class Solution {
public:
/**
* @param root: the given BST
* @param p: the given node
* @return: the in-order predecessor of the given node in the BST
*/
TreeNode * inorderPredecessor(TreeNode * root, TreeNode * p) {
TreeNode * pred = NULL;
while(root) {
if (p->val <= root->val) {
root = root->left;
} else {
if (!pred || root->val > pred->val) {
pred = root;
}
root = root->right;
}
}
return pred;
}
};