LeetBook-二叉搜索树

80 阅读6分钟

二叉搜索树

二叉搜索树 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

验证二叉搜索树

解法1

  1. 递归判断左小右大
  • 坑点:
    • 注意递归不要只比较当前节点的左右,还要注意左小都小,右大都大
    • 有人给测试用例塞了个2147483647,绝了,习惯性用999999😂猛栽
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        return isT(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }
    public boolean isT(TreeNode root, long min, long max) {
        if (root == null) {
            return true;
        }
        if (root.val >= max || root.val <= min) {
            return false;
        }
        return isT(root.left, min, root.val) && isT(root.right, root.val, max);
    }
}

二叉搜索树迭代器

解法1

  1. 直接中序遍历取出来
  2. 然后从list里依次判断
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class BSTIterator {
    List<Integer> result;
    int index = 0;
    public BSTIterator(TreeNode root) {
        result = new ArrayList<>();
        inOrder(result, root);
    }
    
    public int next() {
        return result.get(index++);
    }
    
    public boolean hasNext() {
        return index < result.size();
    }
    public void inOrder(List<Integer> result, TreeNode node) {
        if (node == null) {
            return;
        }
        inOrder(result, node.left);
        result.add(node.val);
        inOrder(result, node.right);
    }
}

/**
 * Your BSTIterator object will be instantiated and called as such:
 * BSTIterator obj = new BSTIterator(root);
 * int param_1 = obj.next();
 * boolean param_2 = obj.hasNext();
 */

解法2

  1. 迭代+栈
  2. 每个节点,将当前节点左节点全部入栈
  3. 逐个出栈
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class BSTIterator {
    TreeNode node;
    Deque<TreeNode> stack;
    public BSTIterator(TreeNode root) {
        node = root;
        stack = new LinkedList<TreeNode>();
    }
    
    public int next() {
        while (node != null) {
            stack.push (node);
            node = node.left;
        }
        node = stack.pop();
        int result = node.val;
        node = node.right;
        return result;
    }
    
    public boolean hasNext() {
        return node != null || !stack.isEmpty();
    }
}

/**
 * Your BSTIterator object will be instantiated and called as such:
 * BSTIterator obj = new BSTIterator(root);
 * int param_1 = obj.next();
 * boolean param_2 = obj.hasNext();
 */

二叉搜索树中的搜索

解法1

简单递归

  1. 等于 -> 返回
  2. 小于 -> 左递归
  3. 大于 -> 右递归
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if (root == null) {
            return null;
        }
        if (root.val == val) {
            return root;
        } else if (root.val > val) {
            return searchBST(root.left, val);
        } else {
            return searchBST(root.right, val);
        }
    }
}

二叉搜索树中的插入操作

解法1

  1. 递归
  2. 小则往左递归
  3. 大则往右递归
  4. 碰到null插入
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) {
            root = new TreeNode(val);
            return root;
        }
        insert(root, val);
        return root;
    }
    public void insert(TreeNode node, int val) {
        if (val > node.val) {
            if (node.right == null) {
                node.right = new TreeNode(val);
                return;
            }
            node = node.right;
        } else {
            if (node.left == null) {
                node.left = new TreeNode(val);
                return;
            }
            node = node.left;
        }
        insert(node, val);
    }
}

删除二叉搜索树中的节点

解法1

  1. 递归
  2. 如果相等
    1. 左树为空,则直接把右树接上
    2. 右树为空,则直接把左树接上
    3. 两边都不为空(二选一)
      • 左树取最大值替掉当前节点
      • 右树取最小值替掉当前节点
  3. 返回root
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) {
            return null;
        }
        if (root.val == key) {
            if (root.left == null) {
                return root.right;
            }
            if (root.right == null) {
                return root.left;
            }
            TreeNode temp = root.left;
            while (temp.right != null) {
                temp = temp.right;
            }
            temp.right = root.right;
            return root.left;
        } else if (root.val < key) {
            root.right = deleteNode(root.right, key);
        } else {
            root.left = deleteNode(root.left, key);
        }
        return root;
    }
}

数据流中的第K大元素

解法1

topK问题,重点

优先队列

class KthLargest {
    Queue<Integer> queue;
    int kkkk;
    public KthLargest(int k, int[] nums) {
        kkkk = k;
        queue = new PriorityQueue<Integer>();
        for (int num : nums) {
            queue.add(num);
        }
    }
    
    public int add(int val) {
        queue.offer(val);
        while (queue.size() > kkkk) {
            queue.poll();
        }
        return queue.peek();
    }
}

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest obj = new KthLargest(k, nums);
 * int param_1 = obj.add(val);
 */

二叉搜索树的最近公共祖先

解法1

直接复用二叉树的最近公共祖先

  1. 递归
  2. 递归自己,如果碰到要找的节点,就返回
  3. 判断左为空就都在右边
  4. 判断右为空就都在左边
  5. 否则就一边一个,返回当前节点
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || root == p || root == q) {
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if (left == null) {
            return right;
        }
        if (right == null) {
            return left;
        }
        return root;
     }
}

解法2

  1. 递归
  2. 先换一下位置,确保p小q大
  3. 如果root和p,q中的一个相等,则return
  4. 如果p小于root,q大于root,则return
  5. 如果root大于q,则向左递归
  6. 如果root小于q,则向右递归
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (p.val > q.val) {
            return lowestCommonAncestor(root, q, p);
        }
        if (root == p || root == q || root.val > p.val && root.val < q.val) {
            return root;
        } else if (root.val > q.val) {
            return lowestCommonAncestor(root.left, p, q);
        } else {
            return lowestCommonAncestor(root.right, p, q);
        }
    }
}

存在重复元素Ⅲ

解法1

【宫水三叶】一题双解:「滑动窗口 & 二分」&「桶排序」解法 - 存在重复元素 III - 力扣(LeetCode)

class Solution {
    long size;
    public boolean containsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) {
        int n = nums.length;
        Map<Long, Long> map = new HashMap<>();
        size = valueDiff + 1L;
        for (int i = 0; i < n; i++) {
            long u = nums[i] * 1L;
            long idx = getIdx(u);
            if (map.containsKey(idx)) {
                return true;
            }
            long l = idx - 1, r = idx + 1;
            if (map.containsKey(l) && u - map.get(l) <= valueDiff) {
                return true;
            }
            if (map.containsKey(r) && map.get(r) - u <= valueDiff) {
                return true;
            }
            map.put(idx, u);
            if (i >= indexDiff) {
                map.remove(getIdx(nums[i - indexDiff] * 1L));
            }
        }
        return false;
    }
    public long getIdx(long u) {
        return u >= 0 ? u / size : ((u + 1) / size) - 1;
    }
}

平衡二叉树

解法1

  • 自顶向下递归
  1. 递归
  2. 如果root为空返回true
  3. 如果左右树的深度差大于1,返回false
  4. 返回判断左右子树是否为平衡二叉树
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) {
            return true;
        }
        int left = deep(root.left);
        int right = deep(root.right);
        if (Math.abs(left - right) > 1) {
            return false;
        }
        return isBalanced(root.left) && isBalanced(root.right);
    }
    public int deep(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return Math.max(deep(root.left), deep(root.right)) + 1;
    }
}

解法2

  • 自底向上递归,解决方法1中deep方法重复调用的问题,先判断左右子树是否平衡,在判断当前节点是否平衡
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        return deep(root) >= 0;
    }
    public int deep(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = deep(root.left);
        int right = deep(root.right);
        if (left == -1 || right == -1 || Math.abs(left - right) > 1) {
            return -1;
        }
        return Math.max(left, right) + 1;
    }
}

将有序数组转换为二叉搜索树

解法1

  1. 有序数组,每次取中点,即为当前节点
  2. 左右节点分别从中间切开的左右两个数组取中点
  3. 依次递归
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        if (nums.length == 0) {
            return null;
        }
        return createTree(nums, 0, nums.length - 1);
    }
    public TreeNode createTree(int[] nums, int start, int end) {
        if (start > end) {
            return null;
        }
        int mid = start + (end - start) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = createTree(nums, start, mid - 1);
        root.right = createTree(nums, mid + 1, end);
        return root;
    }
}