美文网首页二叉树之下
BST 二叉搜索树及相关LeetCode题目

BST 二叉搜索树及相关LeetCode题目

作者: 专职跑龙套 | 来源:发表于2018-03-18 20:53 被阅读21次

    关于我的 Leetcode 题目解答,代码前往 Github:https://github.com/chenxiangcyr/leetcode-answers


    BST 二叉搜索树的插入

    public class Solution {
        /**
         * @param root: The root of the binary search tree.
         * @param node: insert this node into the binary search tree
         * @return: The root of the new binary search tree.
         */
        public TreeNode insertNode(TreeNode root, TreeNode node) {
            if (root == null) {
                return node;
            }
            if (root.val > node.val) {
                root.left = insertNode(root.left, node);
            } else {
                root.right = insertNode(root.right, node);
            }
            return root;
        }
    }
    

    BST 二叉搜索树的删除

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public TreeNode deleteNode(TreeNode root, int key) {
            if(root == null) {
                return null;
            }
    
            // 递归从左子树中删除
            if(root.val > key) {
                root.left = deleteNode(root.left, key);
            }
            // 递归从右子树中删除
            else if(root.val < key) {
                root.right = deleteNode(root.right, key);
            }
            // 要删除当前节点
            else {
                // 如果当前节点没有左子树,则直接返回右子树
                if(root.left == null) {
                    return root.right;
                }
                
                // 如果当前节点没有右子树,,则直接返回左子树
                if(root.right == null) {
                    return root.left;
                }
                
                // 从右子树中找到值最小的节点,将最小值赋值到该节点
                TreeNode min = findMin(root.right);
                root.val = min.val;
                
                // 递归从右子树中删除该最小值
                root.right = deleteNode(root.right, min.val);
            }
            
            return root;
        }
        
        // 在树中找到值最小的节点
        public TreeNode findMin(TreeNode root) {
            while(root.left != null) {
                root = root.left;
            }
            
            return root;
        }
    }
    

    BST 二叉搜索树的搜索使用示例

    LeetCode题目:285. Inorder Successor in BST 中序遍历的后继者
    Given a binary search tree and a node in it, find the in-order successor of that node in the BST.
    Note: If the given node has no in-order successor in the tree, return null.

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        List<TreeNode> list = new ArrayList<>();
        public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
            /*
            方法1:先做中序优先遍历,再找到第一个大于p的node
            */
            /*inorderTravel(root);
            
            if(!list.contains(p)) return null;
            
            for(TreeNode node : list) {
                if(node.val > p.val) {
                    return node;
                }
            }
            
            return null;*/
            
            /*
            方法2:使用递归
            */
            /*if (root == null) return null;
    
            if (root.val <= p.val) {
                // 后继肯定在右子树里
                return inorderSuccessor(root.right, p);
            } else {
                // 后继可能在左子树里,如果找不到,则说明是root
                TreeNode left = inorderSuccessor(root.left, p);
                
                return (left != null) ? left : root;
            }*/
            
            /*
            方法3:使用迭代
            */
            if (root == null) return null;
            
            TreeNode result = null;
            while(root != null) {
                // 后继可能在左子树里,如果找不到,则说明是root
                if(root.val > p.val) {
                    result = root;
                    root = root.left;
                }
                // 后继肯定在右子树里
                else {
                    root = root.right;
                }
            }
            
            return result;
        }
        
        // 中序优先遍历
        public void inorderTravel(TreeNode root) {
            if(root == null) return;
            
            inorderTravel(root.left);
            
            list.add(root);
            
            inorderTravel(root.right);
        }
    }
    

    LeetCode题目:270. Closest Binary Search Tree Value
    Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target.
    Note:

    • Given target value is a floating point.
    • You are guaranteed to have only one unique value in the BST that is closest to the target.
    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        // 使用递归
        public int closestValue(TreeNode root, double target) {
            
            if(root.val == target) {
                return root.val;
            }
            // 在左子树中查找
            else if(root.val > target) {
                if(root.left == null) return root.val;
                
                int closetLeft = closestValue(root.left, target);
                
                if(Math.abs(closetLeft - target) < Math.abs(root.val - target)) {
                    return closetLeft;
                } else {
                    return root.val;
                }
            }
            // 在右子树中查找
            else {
                if(root.right == null) return root.val;
                
                int closetRight = closestValue(root.right, target);
                
                if(Math.abs(closetRight - target) < Math.abs(root.val - target)) {
                    return closetRight;
                } else {
                    return root.val;
                }
            }
        }
        
        // 使用迭代
        public int closestValueIterative(TreeNode root, double target) {
            int closestVal = root.val; 
            while(root != null){ 
                //update closestVal if the current value is closer to target
                closestVal = (Math.abs(target - root.val) < Math.abs(target - closestVal))? root.val : closestVal;
                if(closestVal == target){   //already find the best result
                    return closestVal;
                }
                root = (root.val > target)? root.left: root.right;   //binary search
            }
            return closestVal;
        }
    }
    

    LeetCode题目:272. Closest Binary Search Tree Value II
    Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.
    Note:

    • Given target value is a floating point.
    • You may assume k is always valid, that is: k ≤ total nodes.
    • You are guaranteed to have only one unique set of k values in the BST that are closest to the target.

    Follow up:
    Assume that the BST is balanced, could you solve it in less than O(n) runtime (where n = total nodes)?

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public List<Integer> closestKValues(TreeNode root, double target, int k) {
            List<Integer> ret = new LinkedList<>();
            // 找到target的后继结点
            Stack<TreeNode> succ = new Stack<>();
            initializeSuccessorStack(root, target, succ);
            
            // 找到target的前驱结点
            Stack<TreeNode> pred = new Stack<>();
            initializePredecessorStack(root, target, pred);
            
            if(!succ.isEmpty() && !pred.isEmpty() && succ.peek().val == pred.peek().val) {
                getNextPredecessor(pred);
            }
            
            while(k > 0) {
                if(succ.isEmpty()) {
                    ret.add(getNextPredecessor(pred));
                } else if(pred.isEmpty()) {
                    ret.add(getNextSuccessor(succ));
                } else {
                    double succ_diff = Math.abs((double)succ.peek().val - target);
                    double pred_diff = Math.abs((double)pred.peek().val - target);
                    if(succ_diff < pred_diff) {
                        ret.add(getNextSuccessor(succ));
                    } else {
                        ret.add(getNextPredecessor(pred));
                    }
                }
                
                k--;
            }
            return ret;
        }
    
        // 找到target的后继结点
        private void initializeSuccessorStack(TreeNode root, double target, Stack<TreeNode> succ) {
            while(root != null) {
                if(root.val == target) {
                    succ.push(root);
                    break;
                } else if(root.val > target) {
                    succ.push(root);
                    root = root.left;
                } else {
                    root = root.right;
                }
            }
        }
    
        // 找到target的前驱结点
        private void initializePredecessorStack(TreeNode root, double target, Stack<TreeNode> pred) {
            while(root != null){
                if(root.val == target){
                    pred.push(root);
                    break;
                } else if(root.val > target) {
                    root = root.left;
                } else{
                    pred.push(root);
                    root = root.right;
                }
            }
        }
        
        // 下一个后继结点
        private int getNextSuccessor(Stack<TreeNode> succ) {
            TreeNode curr = succ.pop();
            int ret = curr.val;
            
            curr = curr.right;
            while(curr != null) {
                succ.push(curr);
                curr = curr.left;
            }
            
            return ret;
        }
    
        // 下一个前驱结点
        private int getNextPredecessor(Stack<TreeNode> pred) {
            TreeNode curr = pred.pop();
            int ret = curr.val;
            
            curr = curr.left;
            while(curr != null) {
                pred.push(curr);
                curr = curr.right;
            }
            
            return ret;
        }
    }
    

    BST 二叉搜索树的扩展使用示例

    LeetCode题目:315. Count of Smaller Numbers After Self
    You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

    Example:
    Given nums = [5, 2, 6, 1]
    To the right of 5 there are 2 smaller elements (2 and 1).
    To the right of 2 there is only 1 smaller element (1).
    To the right of 6 there is 1 smaller element (1).
    To the right of 1 there is 0 smaller element.
    Return the array [2, 1, 1, 0].

    class Solution {
        class TreeNode {
            int val;
            int count; // **从左往右**,小于该val的数字的数目
            int duplicates; // 该val对应的数字的重复个数
            
            TreeNode left;
            TreeNode right;
            
            TreeNode(int val) {
                this.val = val;
            }
        }
        
        public List<Integer> countSmaller(int[] nums) {
            Integer[] result = new Integer[nums.length];
            TreeNode root = null;
            
            // 从右往左以此插入数字
            for(int i = nums.length - 1; i >= 0; i--) {
                root = insert(nums[i], root, result, i, 0);
            }
            
            return Arrays.asList(result);
        }
        
        // 将值为num的节点插入
        public TreeNode insert(int num, TreeNode node, Integer[] result, int idx, int preSum) {
            // 创建节点
            if(node == null) {
                node = new TreeNode(num);
                node.count = 0;
                node.duplicates = 1;
                
                result[idx] = preSum;
            }
            // 更新节点
            else if (node.val == num) {
                node.duplicates++;
                
                result[idx] = preSum + node.count;
            }
            // 在左子树添加
            else if (node.val > num) {
                node.count++;
                
                node.left = insert(num, node.left, result, idx, preSum);
            }
            // 在右子树添加
            else {
                node.right = insert(num, node.right, result, idx, preSum + node.duplicates + node.count);
            }
            
            return node;
        }
        
    }
    

    LeetCode题目:493. Reverse Pairs
    Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].
    You need to return the number of important reverse pairs in the given array.

    Example1:
    Input: [1,3,2,3,1]
    Output: 2

    Example2:
    Input: [2,4,3,5,1]
    Output: 3

    class Solution {
        class TreeNode {
            int val;
            int count; // val大于等于该val的数字的个数
            
            TreeNode left;
            TreeNode right;
            
            TreeNode(int val) {
                this.val = val;
            }
        }
        
        // 将值为num的节点插入
        public TreeNode insert(int num, TreeNode node) {
            // 创建节点
            if(node == null) {
                node = new TreeNode(num);
                node.count = 1;
            }
            // 更新节点
            else if (node.val == num) {
                node.count++;
            }
            // 在左子树添加
            else if (node.val > num) {
                node.left = insert(num, node.left);
            }
            // 在右子树添加
            else {
                // 新增节点比该节点大
                node.count++;
                
                node.right = insert(num, node.right);
            }
            
            return node;
        }
        
        // 查找target
        public int search(long target, TreeNode node) {
            if (node == null) {
                return 0;
            }
            else if (node.val == target) {
                return node.count;
            }
            // 在左子树查找
            else if (node.val > target) {
                return node.count + search(target, node.left);
            }
            // 在右子树查找
            else {
                return search(target, node.right);
            }
        }
        
        public int reversePairs(int[] nums) {
            
            int count = 0;
            TreeNode head = null;
            
            // 从左往右以此插入数字
            for(int i = 0; i < nums.length; i++) {
                // 先查找在之前的数字中,有多少个val大于等于nums[i] * 2l + 1的数字
                count += search(nums[i] * 2l + 1, head);
                
                // 再插入该数字
                head = insert(nums[i], head);
            }
            
            return count;
        }
    }
    

    LeetCode题目:173. Binary Search Tree Iterator
    Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST.

    Calling next() will return the next smallest number in the BST.

    Note: next() and hasNext() should run in average O(1) time and uses O(h) memory, where h is the height of the tree.

    /**
     * Definition for binary tree
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    
    public class BSTIterator {
        Stack<TreeNode> stack;
        
        public BSTIterator(TreeNode root) {
            stack = new Stack<TreeNode>();
            
            if(root != null) {
                stack.push(root);
                
                // 将最左边的路径放入栈中
                while(root.left != null) {
                    stack.push(root.left);
                    root = root.left;
                }
            }
        }
    
        /** @return whether we have a next smallest number */
        public boolean hasNext() {
            return !stack.empty();
        }
    
        /** @return the next smallest number */
        public int next() {
            if(stack.empty()) return 0;
            
            TreeNode node = stack.pop();
            int result = node.val;
            
            node = node.right;
            
            if(node != null) {
                stack.push(node);
    
                // 将最左边的路径放入栈中
                while(node.left != null) {
                    stack.push(node.left);
                    node = node.left;
                }
            }
            
            return result;
        }
    }
    
    /**
     * Your BSTIterator will be called like this:
     * BSTIterator i = new BSTIterator(root);
     * while (i.hasNext()) v[f()] = i.next();
     */
    

    一点讨论

    在上一个的题目中,BST中插入,删除,搜索的时间复杂度,最好情况为 O(logN)
    但是BST 二叉搜索树不一定是平衡的,如果原数组是升序或者降序的,在插入过程中,会导致生成的BST 二叉搜索树极度不平衡,插入,删除,搜索的时间复杂度,最坏情况为 O(N)

    为此,我们可以考虑使用平衡的二叉搜索树,例如 红黑树,AVL树,但是其实现起来比较复杂。

    有没有哪种方法,既可以保证 O(logN) 的时间复杂度,又比较容易实现?请参见 树状数组Binary Indexed Tree及相关LeetCode题目

    相关文章

      网友评论

        本文标题:BST 二叉搜索树及相关LeetCode题目

        本文链接:https://www.haomeiwen.com/subject/qbkyfftx.html