给定一棵二叉搜索树,请找出其中第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大的数。
代码:
class Solution {
private int res, cnt = 0;
public int kthLargest(TreeNode root, int k) {
// 使用中序遍历(右根左) 遍历到第k个直接返回.
inorder(root, k);
return res;
}
void inorder(TreeNode root, int k) {
if (root == null) return;
inorder(root.right, k);
if ((++cnt) == k) {
res = root.val;
return;
}
inorder(root.left, k);
}
}
时间复杂度:O(n)遍历二叉树
空间复杂度:O(1)
方法二:中序遍历(左根右)
遍历一遍,先用可变数组存起来(ArrayList),然后直接get(len - k)即可
代码:
class Solution {
private ArrayList<Integer> list = new ArrayList<>();
public int kthLargest(TreeNode root, int k) {
// 中序遍历 把遍历结果放到数组里面 然后取出 1 : size - 1 k : size - k
inorder(root);
return list.get(list.size() - k);
}
void inorder(TreeNode root) {
if (root == null) return;
inorder(root.left);
list.add(root.val);
inorder(root.right);
}
}
时间复杂度:O(n)遍历二叉树
空间复杂度:O(n)
方法三:优先队列
最近看了一些优先队列,然后一看到这个题,我一激动,这优先队列可以做啊,连二叉搜索树这个条件都直接忽略了。
用优先队列的话,就是使用优先队列,控制队列的size为k即可。Java中的优先队列是默认队首元素最小(即从小到大)。如果队列size < k则直接add进入队列,否则就要比较下队首元素和当前元素的大小,比队首元素大才能进,这样遍历完整个数组,就能保留k个数据,它们就是队列中前k大的数据。只要return priorityQueue.peek()即可。
代码:
class Solution {
public int kthLargest(TreeNode root, int k) {
// 使用优先队列 遍历树 获取到队首元素即可.
PriorityQueue<Integer> pq = new PriorityQueue<>();
recur(root, pq, k);
return pq.peek();
}
void recur(TreeNode root, PriorityQueue<Integer> pq, int k) {
if (root == null) return;
if (pq.size() < k) {
pq.add(root.val);
} else if (root.val > pq.peek()) {
pq.remove();
pq.add(root.val);
}
recur(root.left, pq, k);
recur(root.right, pq, k);
}
}
时间复杂度:O(n)+O(lgk)遍历二叉树 + 优先队列插入删除元素
空间复杂度:O(k)只需要在优先队列中存k个元素