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

关于我的 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 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 closestKValues(TreeNode root, double target, int k) {
        List ret = new LinkedList<>();
        // 找到target的后继结点
        Stack succ = new Stack<>();
        initializeSuccessorStack(root, target, succ);
        
        // 找到target的前驱结点
        Stack 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 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 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 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 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 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 stack;
    
    public BSTIterator(TreeNode root) {
        stack = new Stack();
        
        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题目)