230_二叉搜索树中第K小的元素
package 二叉树.二叉搜索树; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; /** * https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/ * * @author Huangyujun * */ public class _230_二叉搜索树中第K小的元素 { // 有bug:原因是最小不一定只是左子树的左,因为k 的原因可能有机会出现在右子树的左呀 // public int kthSmallest(TreeNode root, int k) { // small(root); // return list.get(list.size() - k); // } // List<Integer> list = new ArrayList<>(); // public int small(TreeNode root) { // if(root == null) return 0; // list.add(small(root.left)); // return root.val; // } //方法一:中序遍历(实现升序) public int kthSmallest(TreeNode root, int k) { inorder(root); return list.get(k - 1); } List<Integer> list = new ArrayList<>(); public void inorder(TreeNode root) { if(root == null) return; inorder(root.left); //拿到当前结点 list.add(root.val); inorder(root.right); } //就是利用中序遍历(特点是二叉搜索树的中序遍历是从小到大啦,利用其特点,遍历到第k 次就能拿到 第k小) //因为升序的特点,应该在中序的过程(不断的拿最小、第二小的过程,到第k 小的时候就刹车了) //递归(二叉树的中序遍历递归): class Solution { private int count = 0; private int ans = -1; public void dfs(TreeNode root, int k){ if (null == root || ans != -1) return; dfs(root.left, k); ++count; //当是第k小时拿到值,然后判断调整判断条件( ans != -1 ),退出循环(递归 ) if (count == k) ans = root.val; dfs(root.right, k); } public int kthSmallest(TreeNode root, int k) { dfs(root, k); return ans; } } //非递归(二叉树的中序遍历递归): class Solution2 { public int kthSmallest(TreeNode root, int k) { Deque<TreeNode> stack = new ArrayDeque<TreeNode>(); while (root != null || !stack.isEmpty()) { while (root != null) { stack.push(root); root = root.left; } root = stack.pop(); --k; if (k == 0) { break; } root = root.right; } return root.val; } } // (本思路算法时间很不优秀)通过 map 存储了每个结点下对应的所有结点数量(就是因为这个步骤,导致算法时间不优秀了): //思路可以看看: /** * 对当前结点 node 进行如下操作: 如果 node 的左子树的结点数 left 小于 k-1k−1,则第 kk 小的元素一定在node 的右子树中,令 node 等于其的右子结点,k 等于 k−left−1,并继续搜索; 如果 node 的左子树的结点数 left 等于 k−1,则第 k 小的元素即为 node ,结束搜索并返回 node 即可; 如果 node 的左子树的结点数 left 大于 k−1,则第 k 小的元素一定在 node 的左子树中,令 node 等于其左子结点,并继续搜索。 * @author Huangyujun * */ class Solution3 { public int kthSmallest(TreeNode root, int k) { MyBst bst = new MyBst(root); return bst.kthSmallest(k); } class MyBst { TreeNode root; //当前根结点,对应的结点数量其所有结点的数量 Map<TreeNode, Integer> nodeNum; public MyBst(TreeNode root) { this.root = root; this.nodeNum = new HashMap<TreeNode, Integer>(); countNodeNum(root); } // 返回二叉搜索树中第k小的元素 public int kthSmallest(int k) { TreeNode node = root; while (node != null) { int left = getNodeNum(node.left); if (left < k - 1) { node = node.right; k -= left + 1; } else if (left == k - 1) { break; } else { node = node.left; } } return node.val; } // 统计以node为根结点的子树的结点数 private int countNodeNum(TreeNode node) { if (node == null) { return 0; } nodeNum.put(node, 1 + countNodeNum(node.left) + countNodeNum(node.right)); return nodeNum.get(node); } // 获取以node为根结点的子树的结点数(getOrDefault(node, 0); 这个方法是当非空是返回原本的值,否则返回第二个参数(默认值)) private int getNodeNum(TreeNode node) { return nodeNum.getOrDefault(node, 0); } } } }