每日一题 - 剑指 Offer 54. 二叉搜索树的第k大节点

Posted id-wangqiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一题 - 剑指 Offer 54. 二叉搜索树的第k大节点相关的知识,希望对你有一定的参考价值。

题目信息

  • 时间: 2019-07-04

  • 题目链接:Leetcode

  • tag:二叉搜索树 中序遍历 递归

  • 难易程度:中等

  • 题目描述:

    给定一棵二叉搜索树,请找出其中第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. 1 ≤ k ≤ 二叉搜索树元素个数

解题思路

本题难点

二叉排序树:根节点的值大于左子树的值,小于右子树的值。查找第K大节点。

具体思路

二叉搜索树的中序遍历为 递增序列 ,易得二叉搜索树的 中序遍历倒序递减序列

求 “二叉搜索树第 k大的节点” 可转化为求 “此树的中序遍历倒序的第 k个节点”。

  • 中序遍历

    // 打印中序遍历
    void dfs(TreeNode root) {
        if(root == null) return;
        dfs(root.left); // 左
        System.out.println(root.val); // 根
        dfs(root.right); // 右
    }
    
  • 中序遍历的倒序

    // 打印中序遍历倒序
    void dfs(TreeNode root) {
        if(root == null) return;
        dfs(root.right); // 右
        System.out.println(root.val); // 根
        dfs(root.left); // 左
    }
    

求第 k大节点,需要实现以下 三项工作

  • 递归遍历时计数,统计当前节点的序号;
  • 递归到第 k个节点时,应记录结果 res ;
  • 记录结果后,后续的遍历即失去意义,应提前终止(即返回)。

提示:在获得res结果时,增加一个return语句可以避免之后的无效迭代dfs(root.left);

代码

class Solution {
  ////形参k不能随着dfs的迭代而不断变化,为了记录迭代进程和结果,引入类变量count和res
    int count=0, res=0;
    public int kthLargest(TreeNode root, int k) {
        this.count = k;
        dfs(root);
        return res;
    }

    public void dfs(TreeNode root){
      // 若 k=0 ,代表已找到目标节点,无需继续遍历,因此直接返回;
        if(root == null || count == 0){
            return;
        }
      //递归右子树
        dfs(root.right);
      //统计序号: 执行 k=k?1 (即从 k 减至 0 );
      //记录结果: 若 k=0 ,代表当前节点为第 k 大的节点,因此记录 res=root.val ;
        if(--count == 0){
            res = root.val;
            return;
        }
      //递归左子树
        dfs(root.left);
    }
}

复杂度分析:

  • 时间复杂度 O(N) :当树退化为链表时(全部为右子节点),无论 k的值大小,递归深度都为 N,占用 O(N) 时间。
  • 空间复杂度 O(N) :当树退化为链表时(全部为右子节点),系统使用 O(N) 大小的栈空间。

其他优秀解答

解题思路

中序遍历倒序的非递归算法。

代码

class Solution {
    public int kthLargest(TreeNode root, int k) {
        int count = 1;
        Stack<TreeNode> stack = new Stack<>();
        while (Objects.nonNull(root) || !stack.empty()) {
            while (Objects.nonNull(root)) {
                stack.push(root);
                root = root.right;
            }
            TreeNode pop = stack.pop();
            if (count == k) {
                return pop.val;
            }
            count++;
            root = pop.left;
        }
        return 0;
    }
}

以上是关于每日一题 - 剑指 Offer 54. 二叉搜索树的第k大节点的主要内容,如果未能解决你的问题,请参考以下文章

每日一题 - 剑指 Offer 55 - II. 平衡二叉树

乱序版 ● 剑指offer每日算法题打卡题解—— 搜索与回溯算法(题号 40,45,61)

乱序版 ● 剑指offer每日算法题打卡题解—— 搜索与回溯算法 (题号26,27, 28)

乱序版 ● 剑指offer每日算法题打卡题解——搜索与回溯算法(题号37,38)

每日一题 - 剑指 Offer 55 - I. 二叉树的深度

乱序版 ● 剑指offer每日算法题打卡题解—— 分治算法(题号7,33,64)