LeetCode:Binary Search Tree相关题目合集

Validate Binary Search Tree

Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.

解题关键:不能只比较当前root.val与left.val和right.val满不满足BST的定义,需要在递归中记录上一层根节点的值来检测是否满足BST有效性。

Example:

                    5

                  /    \

                4      6

              /   \

            3     7

这是一个无效的BST,虽然4的左右孩子都满足 3 < 4 < 7,但是7大于4的根节点5.

Solution 1: Recursive Traversal

Time Complexity: O(n) Space Complexity: O(1)

public class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValid(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
    }

    private boolean isValid(TreeNode root, int min, int max){
        if(root == null){
            return true;
        }

        if(root.val <= min || root.val >= max){
            return false;
        }

        return isValid(root.left, min, root.val) && isValid(root.right, root.val, max);
    }
}

以上代码有一个Bug,在极端情况下,root.val == Integer.MAX_VALUE or root.val == Integer.MIN_VALUE 以上代码会无法正确判断。
先用笨办法解决这个Bug,让我们看看Solution2.

Solution2: In-order Traversal
Time Complexity: O(n) Space Complexity: O(n)

public class Solution {
    public boolean isValidBST(TreeNode root) {
        List<Integer> in = inorder(root);
        for(int i = 1; i < in.size(); i++){
            if(in.get(i) <= in.get(i - 1)){
                return false;
            }
        }
        return true;
    }

    private List<Integer> inorder(TreeNode root){
        List<Integer> result = new ArrayList<Integer>();
        if(root == null){
            return result;
        }
        List<Integer> left = inorder(root.left);
        List<Integer> right = inorder(root.right);
        result.addAll(left);
        result.add(root.val);
        result.addAll(right);
        return result;
    }
}

有没有更好的办法? 答案是肯定,我们可以把Solution1和Solution2的解法结合起来并通过设置一个flag来规避Solution1中的极端情况。

Solution 3: In-order Traversal with flag
Time Complexity: O(n) Space Complexity: O(1)

public class Solution {
    private int lastVal = Integer.MIN_VALUE; //lastVal to store previous root value
    private boolean firstNode = true; //Flag

    public boolean isValidBST(TreeNode root) {
        //Base case
        if (root == null) {
            return true;
        }
        //Check left sub-tree
        if (!isValidBST(root.left)) {
            return false;
        }
        //Check current root
        if (!firstNode && lastVal >= root.val) {
            return false;
        }
        firstNode = false;
        lastVal = root.val;
        //Check right sub-tree
        if (!isValidBST(root.right)) {
            return false;
        }
        return true;
    }
}

Recover Binary Search Tree

Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
Note: A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?
解题思路:首先我们得找出这个两个被swapped的节点。如何找?最笨的方法是用一个List将中序遍历的结果存起来,通过遍历这个List来找到inversed的地方。但是这个需要O(n)的额外空间肯定不是面试官想要的。我们可以直接在In-order的过程中找出这两个节点。
我们可以先画一个简单的BST找到其中的规律。

Example:
            10
            /\
           8 12
          / \
         7   9
in-order: 7 8 9 10 12
1.swap 9 & 12
            10
            /\
           8  9
          / \
         7  12
in-order: 7 8 12 10 9
2.swap 8 & 9
            10
            /\
           9 12
          / \
         7   8
in-order: 7 9 8 10 12
3.swap 7 & 10
            7
            /\
           8 12
          / \
         10  9
in-order: 10 8 9 7 12

这里我们发现两个被swapped的节点,第一个永远是第一次发现inverse的前一个。如果两个节点相邻那么第二个节点是紧接第一个的下一个。如果两个节点不相邻,那么就是再次发现inverse的后一个。
所以这里我们设置了3个全局变量:first, second, prev。
如果第一次发现inverse,那么就将first = prev。并second = root。
如果再次发现inverse,那么将再次更新second = root.

public class Solution {

    private TreeNode first;
    private TreeNode second;
    private TreeNode prev = new TreeNode(Integer.MIN_VALUE);

    public void recoverTree(TreeNode root) {
        helper(root);
        int tmp = first.val;
        first.val = second.val;
        second.val = tmp;
    }

    private void helper(TreeNode root){
        if(root == null){
            return;
        }
        helper(root.left);
        if(first == null && prev.val >= root.val){
            first = prev;
        }
        if(first != null && prev.val >= root.val){
            second = root;
        }
        prev = root;
        helper(root.right);
    }
}

Successor of Binary Search Tree

In Binary Tree, Inorder successor of a node is the next node in Inorder traversal of the Binary Tree. Inorder Successor is NULL for the last node in Inoorder traversal.
In Binary Search Tree, Inorder Successor of an input node can also be defined as the node with the smallest key greater than the key of input node. So, it is sometimes important to find next node in sorted order.
Example
In the above diagram, inorder successor of 8 is 10, inorder successor of 10 is 12 and inorder successor of 14 is 20.

解题思路:BST的题目一般都需要手动画几个cases来思考。例如上图中8的successor是10,10是8右孩子12的left-most child。
如果一个节点有右孩子那么它的successor一定是它的left-most child of its right child(如果right child没有左孩子那么就是右孩子自己)。
如果一个节点没有右孩子,那么它的successor就得从root开始搜索了。按照BST的特性开始搜索,碰到比输入节点大的就记录下来。搜索到输入节点或者当前节点为Null就退出搜索。

class Solution {
    public TreeNode getSuccessor(TreeNode root, TreeNode node){
        //If node has right child.
        if(node.right != null){
            TreeNode cur = node.right;
            while(cur.left != null){
                cur = cur.left;
            }
            return cur;
        }
        //If node do not has right child, we need start search from root.
        TreeNode successor = null;
        while(root != null){
            if(root.val > node.val){
                successor = root;
                root = root.left;
            }else if(root.val < node.val){
                root = root.right;
            }else{
                break;
            }
        }
        return successor;
    }
}

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.

用一个stack来parents path。每次从stack中pop出来一个元素时,将它紧接着比它大的元素Push到stack中。

public class BSTIterator {
    //@param root: The root of binary tree.

    private Stack<TreeNode> stack;

    public BSTIterator(TreeNode root) {
        stack = new Stack<TreeNode>();
        if(root != null) pushNext(root);
    }

    //@return: True if there has next node, or false
    public boolean hasNext() {
        return !stack.isEmpty();
    }

    //@return: return next node
    public TreeNode next() {
        TreeNode node = stack.pop();
        if(node.right != null){
            pushNext(node.right);
        }
        return node;
    }

    //This function is for pushing successors of current node
    private void pushNext(TreeNode node){
        if(node == null){
            return;
        }
        stack.push(node);
        TreeNode left = node.left;
        while(left != null){
            stack.push(left);
            left = left.left;
        }
    }

Largest Binary Search Tree (BST) in a Binary Tree

Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest means subtree with largest number of nodes in it.

LeetCode article里面的一个题目。面试真题。
一开始Naive的思路,分三步:
(1) Mark 所有的TreeNode 是不是BST(给node.isBST赋值)
(2) Mark所有的TreeNode 包括自己在内的拥有的子节点个数。(给node.num赋值)
(3) 从Root开始查找,遍历整个二叉树。用一个全局变量记录最大BST(maxBST = node.num if node.isBST && node.num > maxBST)

(1)可以通过in-order遍历完成O(n). (2)正常遍历一遍O(n). (3)也是O(n).
所以总的时间复杂度是O(3n).
同学说能不能不做预处理,不用全局变量,直接做,把1, 2, 3合并在一起。那我只能恶心的修改TreeNode这个类。把所以需要记录的数值都存在新的TreeNode类里。

class Node{
    Node left;
    Node right;
    int val;
    int min; //minimum value of this subtree
    int max; //maximum value of this subtree
    int num; //number of nodes in this subtree
    int maxBST; //maximum number of BST in this subtree

    public Node(int min, int max, int num, int maxBST){
        this.min = min;
        this.max = max;
        this.num = num;
        this.maxBST = maxBST;
    }

    public Node(int v){
        this.val = v;
    }
}

基本思路是中序遍历。首先左子树是不是BST。再检测右子树是不是BST。maxBST有3种情况:
1、当前root的子树是BST(root.maxBST = left.maxBST + right.maxBST + 1)
2、当前root的子树不是BST,当前子树的最大BST等于左子树或者右子树的最大BST(root.maxBST = Math.max(left.maxBST, right.maxBST))

这里min, max是bottom-top的方式传上去的,因为如果当前节点的子树不是BST那么整个树肯定也不是BST。

class LargestBSTinBinaryTree {
    public int findLargestBSTinBinaryTree(Node root){
        return findLargestBST(root).maxBST;
    }

    private Node findLargestBST(Node root){
        /*因为是in-order遍历,我们总是先检测左子树再检测右子树,所以
        我们不需要记录我们是上一个节点的left child还是right child*/
        if(root == null){
            return new Node(Integer.MAX_VALUE, Integer.MIN_VALUE, 0, 0);
        }
        boolean isBST = true;
        /*Check left-subtree*/
        Node leftRoot = findLargestBST(root.left);
        if(leftRoot.maxBST != leftRoot.num || leftRoot.max >= root.val){
            isBST = false;
        }
        /*Check right-subtree*/
        Node rightRoot = findLargestBST(root.right);
        if(rightRoot.maxBST == rightRoot.num){

        }
        if(rightRoot.maxBST != rightRoot.num || rightRoot.min <= root.val){
            isBST = false;
        }
        /*Set number of nodes that current root has*/
        root.num = leftRoot.num + rightRoot.num + 1;
        /*Update maxBST of current root*/
        if(isBST){
            root.maxBST = root.num;
        }else{
            root.maxBST = Math.max(leftRoot.maxBST, rightRoot.maxBST);
        }
        /*Update min-max value and pass it from bottom to top*/
        root.min = leftRoot.max == Integer.MIN_VALUE ? root.val : Math.min(root.val, leftRoot.max);
        root.max = rightRoot.min == Integer.MAX_VALUE ? root.val : Math.max(root.val, rightRoot.min);
        return root;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值