剑指[54]_找出二分搜索树的第K大节点

题目来源:剑指 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);
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小智RE0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值