(一)题目
给定一个二叉搜索树的根节点 root
,和一个整数 k
,请你设计一个算法查找其中第 k
小的元素(从 1 开始计数)。
示例 1:
输入:root = [3,1,4,null,2], k = 1 输出:1
示例 2:
输入:root = [5,3,6,2,4,null,null,1], k = 3 输出:3
提示:
- 树中的节点数为
n
。 1 <= k <= n <= 10^4
0 <= Node.val <= 10^4
(二)分析
二叉搜索树
具有如下性质:
结点的左子树只包含小于当前结点的数。
结点的右子树只包含大于当前结点的数。
所有左子树和右子树自身必须也是二叉搜索树。
二叉树的中序遍历即按照访问左子树——根结点——右子树的方式遍历二叉树;在访问其左子树和右子树时,我们也按照同样的方式遍历;直到遍历完整棵树。(二叉搜索树的中序遍历为一个递增序列)
因此本题转化为对二叉树进行中序遍历,常见的遍历方式有:递归和迭代(使用栈)
方法一:递归
/**
* 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:
void findk(TreeNode* root,int &t,int k,int& val){
if(root==NULL|| val!=-1) return ;
findk(root->left,t,k,val);
t++;
if(t==k){
val=root->val;
return ;
}
findk(root->right,t,k,val);
}
int kthSmallest(TreeNode* root, int k) {
int val=-1;
int t=0;
findk(root,t,k,val);
return val;
}
};
方法二:迭代(后进先出)
(1)当栈不为空时,判断栈顶元素top节点是否有左节点,或左节点已经被访问过
(2)有左孩子且左孩子没有被访问过,则将左孩子节点入栈,
(3)若是没有则访问该栈顶元素,并判断其是否有右孩子
(4)有右孩子则将右孩子放入栈尾
/**
* 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:
int kthSmallest(TreeNode* root, int k) {
stack<TreeNode*>list;
int t=0;
map<TreeNode*,int>haved;
TreeNode* p=root;
if(p!=NULL)list.push(p);
while(!list.empty()){
TreeNode* top=list.top();
if(top->left!=NULL&& haved.find(top->left)==haved.end() ){
//左节点存在且未被访问
list.push(top->left);
}
else{
//访问当前top节点,并出栈
haved[top]++;
t++;
if(t==k){
return top->val;
}
list.pop();
//查看右节点,存在则入栈
if(top->right!=NULL){
list.push(top->right);
}
}
}
return 0;
}
};