230. Kth Smallest Element in a BST
Given a binary search tree, write a function kthSmallest
to find the kth smallest element in it.
Note:
You may assume k is always valid, 1 ≤ k ≤ BST's total elements.
Example 1:
Input: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
Output: 1
Example 2:
Input: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
Output: 3
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?
题目链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/solution/
思路
对BST中序遍历可得到递增序列,因此总体的解题思路是借助中序遍历,在中序是判断当前节点是否是第k个。
法一:递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
return findk(root, k)->val;
}
TreeNode* findk(TreeNode* root, int &k){
if(!root) return NULL;
auto l = findk(root->left, k);
--k;
if(k==0) return root;
auto r = findk(root->right, k);
return (l?l:r);
}
};
法二:非递归
对中序遍历用非递归方法实现。
我想到的方法:在遍历到父节点时,不能将自身弹出,在将左孩子入栈前先加一个空节点,用来标记当前节点已经历第一次遍历,使得在下一次遍历(中序)的时候访问完就弹出。
别人的方法:套两个while循环,一个管不断将左孩子压栈,一个管整个树的遍历是否完成。
明显别人的方法比我的优雅许多,里层while就是对压栈思路的原始翻译,两个while嵌套的使用学习下。
非迭代的运行速度更快,可以在找到元素时直接终止程序。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
stack<TreeNode*> record;
while(true){
while(root){
record.push(root);
root = root->left;
}
root = record.top();
record.pop();
if(--k == 0) return root->val;
else root = root->right;
}
}
};
法三:修改节点数据结构
题目最后问频繁根据排名查找元素,可以在节点数据结构中加一个变量:记录以当前节点为根节点的子树上有多少个节点。
则查找时能根据数量关系,直接能确定走向目标节点的路径。
在本题给的数据结构中不太好实现。