zoukankan      html  css  js  c++  java
  • 230_二叉搜索树中第K小的元素

    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);
                }
            }
        }
    
        
    }

    本文来自博客园,作者:一乐乐,转载请注明原文链接:https://www.cnblogs.com/shan333/p/15709277.html

  • 相关阅读:
    [King.yue]EXT.Grid行双击事件
    [King.yue]关于代码调试时的缓存问题的一个解决办法
    [Buffalo]ASP.NET MVC路由映射
    [Tommas] 如何创建自动化功能测试的基本原则
    [Tommas] Web测试中,各类web控件测试点总结
    [Tommas] ERP系统测试用例设计1(转)
    [King.yue]VS2012 无法启动IIS Express Web服务器的解决方案
    原创 html动态表格
    原创 SqlParameter 事务 批量数据插入
    jquery readio checked
  • 原文地址:https://www.cnblogs.com/shan333/p/15709277.html
Copyright © 2011-2022 走看看