每日一題 - 劍指 Offer 54. 二叉搜尋樹的第k大節點

小鏘同學、發表於2020-07-05

題目資訊

  • 時間: 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;
    }
}

相關文章