題目資訊
-
時間: 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;
}
}