一、题目描述
给定一棵二叉搜索树,请找出其中第 k 大的节点的值。
示例1:
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
输出: 4
示例2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 4
限制:
1 ≤ k ≤ 二叉搜索树元素个数
二、思路分析
注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献
思路
由于二叉搜索树的中序遍历为递增序列,可以知道二叉搜索树的中序遍历倒序为递减序列。因此,求二叉搜索树第k大的节点可转化为求此树的中序遍历倒序的第k个节点。
二叉搜索树的中序遍历步骤为:
----递归遍历左子树
----打印根结点
----递归遍历右子树
由上我们可以得出,二叉搜索树的中序遍历的倒叙步骤为:
----递归遍历右子树
----打印根结点
----递归遍历左子树
为求第k
个节点,需要实现以下三项工作:
----递归遍历时计数,统计当前节点的序号
----递归到第k
个节点时,应记录结果res
----记录结果后,后续的遍历即失去意义,应提前终止(即返回)
递归解析:
终止条件:当节点root
为空(越过叶节点),则直接返回
递归右子树:即dfs(root.right)
三项工作:
----提前返回: 若k=0
,代表已找到目标节点,无需继续遍历,因此直接返回
----统计序号: 执行k=k-1
(即从k
减至0
)
----记录结果: 若k=0
,代表当前节点为第k
大的节点,因此记录res=root.val
递归左子树: 即dfs(root.left)
案例分析:
复杂度分析:
时间复杂度 O ( N ) \rm{O(N)} O(N):当树退化为链表时(全部为右子节点),无论k
的值大小,递归深度都为N
,占用O(N)
时间
空间复杂度 O ( N ) \rm{O(N)} O(N):当树退化为链表时(全部为右子节点),系统使用O(N)
大小的栈空间
三、整体代码
整体代码如下
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void dfs(struct TreeNode* root, int *k, int* res){
if(root == NULL) return; //节点为空,代表穿过叶节点了,直接return
dfs(root->right, k, res); //右子树中序遍历
if(*k == 0) return; //如果k为0了,代表已经找到了,直接返回即可
if(--*k == 0) { //如果k--为0,代表当前节点就是第k大的,然后保存当前节点值
*res = root->val;
}
dfs(root->left, k, res); //左子树中序遍历
}
int kthLargest(struct TreeNode* root, int k){
int k_tmp = k; //定义两个变量,每次递归穿地址,这样才能修改这些变量的值
int res = 0;
dfs(root, &k, &res); //从根结点开始进行dfs
return res;
}
运行,测试通过