剑指offer 62. 二叉搜索树的第 k 个结点 & leetcode 精选top面试题 230. 二叉搜索树中第K小的元素
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 }