题目来源:剑指 Offer 54. 二叉搜索树的第k大节点
题目描述
给定一棵二叉搜索树,请找出其中第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
)那个索引上的节点值;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class Solution {
//最终存储中序遍历的集合;
List<Integer> list = new LinkedList<>();
public int kthLargest(TreeNode root, int k) {
if(root == null) throw new RuntimeException("the tree is empty");
//中序遍历,找索引第(size-k)个即可;
// 0 1 2 3 4 5 6 size:7 找第5大的,其实索引为2; size - k;
MiddleOrder(root);
//找第k大的即可;
if(k>list.size()){
//要找的索引小于0了,超出限制;
throw new RuntimeException("Limit Exceeded");
}else {
return list.get(list.size()-k);
}
}
//中序遍历;
private void MiddleOrder(TreeNode root) {
if(root.left!=null) prefixList(root.left);
list.add(root.val);
if(root.right!=null)prefixList(root.right);
}
}
由于用了额外的空间,效果还是稍差一点;
看过题解,大佬的思路是直接逆向中序遍历;本来中序遍历的结果是由小到大的排序;
逆序的话就是由大到小,直接在逆向的过程中操作;大的元素在前面;
比如下面,想找第4大的节点;每次拿到一节点后,这个指定的K值减一个,继续向前找,直到K值为0时;记录结果;且K值为0时就停止遍历;就返回调用处
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class Solution2 {
//定义返回结果,与指定的k;
private int result ;
private int k;
public int kthLargest(TreeNode root, int k) {
this.k=k;
//中序遍历(左中右);反着来(右中左)
reverMiddleOrder(root);
return result;
}
//逆向中序遍历;
private void reverMiddleOrder(TreeNode root) {
if(root == null) return;
//先递归右子树;
reverMiddleOrder(root.right);
//当前结点的处理;
//若目标值已经为0,则返回上一步;(递归要向原调用处返回)
if(k == 0) return;
//目标值已为0,返回结果确定;
if(--k == 0) result = root.val;
//递归左子树;
reverMiddleOrder(root.left);
}
}