一、需求
- 给定一棵二叉搜索树,请找出其中第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
二、集合+中序遍历
2.1 思路分析
- 根据二叉搜索树的特点,其中序遍历的结果即是有序的,那么只要将这个结果保存的数组或集合中,就能轻易的找到第k大的元素;
2.2 代码实现
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
List<Integer> ls = new ArrayList<>();
public int kthLargest(TreeNode root, int k) {
helper(root);
return ls.get(ls.size() - k);
}
//将二叉搜索树按照中序遍历转到集合
public void helper(TreeNode root) {
if(root == null) return;
helper(root.left);
ls.add(root.val);
helper(root.right);
}
}
2.3 复杂度分析
- 时间复杂度为O(n);
- 空间复杂度为O(n);
三、中序遍历逆序
3.1 思路分析
- 二叉搜索树的中序遍历是一个升序序列,其逆序是一个降序序列,那么其升序中第k大的数就是降序是第k个数字,比如1 2 3 4 5,其第2大的数位4,其逆序5 4 3 2 1,第2个数字为4;
- 首先递归右子树,然后对于当前节点,执行 k = k - 1操作,直到 k == 0,将当前节点值保存到res中,然后递归左子树;
- 因为在执行完当前节点的操作后,还需递归左子树,而此时k可能已为0,因此加入递归退出条件 k == 0时,直接退出;
3.2 代码实现
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int res,k;
public int kthLargest(TreeNode root, int k) {
this.k = k;
dfs(root);
return res;
}
public void dfs(TreeNode root) {
if(root == null) {
return;
}
if(k == 0) return;
dfs(root.right);
if(--k == 0) res = root.val;
dfs(root.left);
}
}
3.3 复杂度分析
- 时间复杂度为O(N),当树退化为链表时,无论k值大小,递归深度都为N,占用O(N)的时间;
- 空间复杂度为O(N),当树退化为链表时,系统使用O(N)大小的栈空间;
四、学习地址
作者:Krahets