62. 二叉搜索树的第 k 个结点 & 230. 二叉搜索树中第K小的元素
题目描述
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
法一:中序遍历递归写法
1 class Solution {
2
3 public int i = 0; // 表示当前是第几个结点
4 public int val = -1; // 记录第k个结点的值
5
6 public int kthSmallest(TreeNode root, int k) {
7 // 中序遍历被访问的第k个结点
8 inOrder(root, k);
9 return val;
10 }
11
12 // 中序遍历树的所有结点
13 public void inOrder(TreeNode root, int k){
14 if(root != null && i < k){ // i 如果大于等于k则没必要继续遍历了
15 inOrder(root.left, k);
16 if(++i == k){
17 val = root.val;
18 return;
19 }
20 inOrder(root.right, k);
21 }
22 }
23 }
leetcode 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.2 MB, 在所有 Java 提交中击败了91.65%的用户
复杂度分析:
时间复杂度:O(n)。最多遍历整棵树,所以时间复杂度为O(n)。
空间复杂度:O(n)。递归栈的深度即是空间复杂度,栈的深度取决于树的高度,当树退化成链表时,最空间复杂度为O(n)。
法二:非递归中序遍历
1 class Solution {
2
3 public int kthSmallest(TreeNode root, int k) {
4 // 非递归中序遍历被访问的第k个结点
5 Stack<TreeNode> stack = new Stack<TreeNode>();
6 TreeNode cur = root;
7 int val = 0;
8 while(!stack.isEmpty() || cur != null){
9 while(cur != null){
10 stack.push(cur);
11 cur = cur.left;
12 }
13 cur = stack.pop();
14 if(--k == 0){
15 return cur.val;
16 }
17 cur = cur.right;
18 }
19 return val;
20 }
21 }
leetcode 执行用时:1 ms, 在所有 Java 提交中击败了54.12%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了71.21%的用户
复杂度分析:
时间复杂度:O(n)。最多遍历整棵树,所以时间复杂度为O(n)。
空间复杂度:O(n)。辅助栈的深度即是空间复杂度,栈的深度取决于树的高度,当树退化成链表时,最空间复杂度为O(n)。
法三:
将所有的结点按中序遍历的顺序存入一个ArrayList, 最后取出 第 k 个元素即可
1 import java.util.ArrayList;
2 public class Solution {
3 // 将所有的结点按中序遍历的顺序存入一个ArrayList, 最后取出 第 k 个元素即可
4 ArrayList<TreeNode> arr = new ArrayList<>();
5 TreeNode KthNode(TreeNode pRoot, int k)
6 {
7 if(pRoot == null)
8 return null;
9 inOrder(pRoot);
10 if(k >= 1 && k <= arr.size()) // 如果 k 在 1 和 最大结点数之间
11 return arr.get(k - 1);
12 return null; // 说明 k 超过了节点数
13 }
14
15 void inOrder(TreeNode root){
16 if(root != null){
17 inOrder(root.left);
18 arr.add(root);
19 inOrder(root.right);
20 }
21 }
22 }