剑指 Offer:54 二叉搜索树的第 K 大节点

94 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情

题目

给定一棵二叉搜索树,请找出其中第 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 大的节点

  1. 使用递归的方式,进行中序遍历
  2. 每经历一个父节点时,k--,直到 k == 0 时,返回当前值

代码

/**
 * Definition for a binary tree node.
 */
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

class Solution {

    int res;
    int k;
    public int kthLargest(TreeNode root, int k) {
        this.k = k;
        dfs(root);
        return res;
    }

    public void dfs(TreeNode root) {
        if (root == null) return;
        dfs(root.right);  // 右
        if (--k == 0) {
            res = root.val;
            return;
        }
        dfs(root.left); // 左
    }
}

总结

性能分析

  • 执行耗时:0 ms,击败了 100.00% 的 Java 用户
  • 内存消耗:41 MB,击败了 27.37% 的 Java 用户

解题二:栈

思路

二叉搜索树的特性:左子树的最大值 < 父节点的值 < 右子树的最小值

按照二叉搜索树的特性,我们可以将问题转换为中序遍历二叉树,寻找中序遍历中第 K 大的节点

  1. 使用栈的方式,按照中序遍历,将遍历的节点存入 stack
  2. 每存入一个节点时,k--,直到 k == 0 时,返回当前值

代码

/**
 * Definition for a binary tree node.
 */
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

class Solution {

    public int kthLargest(TreeNode root, int k) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        while (!stack.isEmpty() || root != null) {
            if (root != null) {
                stack.push(root);
                root = root.right;
            } else {
                root = stack.pop();
                if(--k==0){
                    return root.val;
                }
                root = root.left;
            }
        }
        return -1;
    }
}

总结

性能分析

  • 执行耗时:1 ms,击败了 28.81% 的 Java 用户
  • 内存消耗:41.2 MB,击败了 18.17% 的 Java 用户