版权声明:转载请注明出处!谢谢! https://blog.csdn.net/qq_28114615/article/details/86559233
目录
1 题目描述
给定一个二叉搜索树,编写一个函数 kthSmallest
来查找其中第 k 个最小的元素。
说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
输出: 1
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 3
2 题目分析
一看到求第K小的问题,应该会容易想到建立大顶堆来做,但是如果这道题采用大顶堆的方式来做的话,是比较麻烦的,还得转换为数组,这样的话就完全忽视了二叉搜索树本身的特点。
为了利用二叉搜索树的特点,一种可以采取的方法就是对二叉搜索树进行中序遍历,遍历结果必定是个升序数组,当数组长度达到k时,那么数组末尾的元素就是二叉搜索树的第K小元素了。不过这样的话就需要一个大小为O(K)的开辟辅助空间。
为了既利用二叉搜索树的特点,又能减少辅助空间的开销,可以直接对左子树结点进行计数,如果左子树的结点数等于k-1的话,说明当前结点就是第k小的结点了;如果左子树结点数小于k-1的话,说明第k小的结点在当前结点的右边,假设左子树上的结点有num个,那么此时就递归查找右子树上第k-1-num小的元素;如果左子树结点大于k-1的话,说明第k小的结点就在左子树上,那么就递归查找左子树上第k小的元素。
3 代码实现
3.1 中序遍历方法
int kthSmallest(TreeNode* root, int k) {
vector<int>nums;
int count=0; //用于计数
midOrder(root,nums,k,count);
return nums[k-1];
}
void midOrder(TreeNode* root,vector<int>& nums,int k,int& count)
{
if(!root||count==k)return ; //如果计数到k,则直接返回
midOrder(root->left,nums,k,count);
nums.push_back(root->val);
count++; //计数加一
midOrder(root->right,nums,k,count);
return ;
}
3.2 结点计数方法
int kthSmallest(TreeNode* root, int k) {
int num=count(root->left); //计算左子树上结点数目
if(num==k-1)return root->val; //左子树上结点数目等于K-1,当前结点即是第k小结点
if(num>k-1)return kthSmallest(root->left,k); //左子树上结点数目大于K-1,说明第k小结点在左子树上
return kthSmallest(root->right,k-1-num);//左子树上结点数目小于K-1,说明第k小结点在右子树上
}
int count(TreeNode* root)
{
if(!root)return 0;
return count(root->left)+count(root->right)+1;
}