LeetCode

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

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

  1. class Solution {
  2. public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
  3. if (root == null || root == p || root == q) {
  4. return root;
  5. }
  6. // 只在左边
  7. if (root.val > p.val && root.val > q.val) {
  8. return lowestCommonAncestor(root.left, p, q);
  9. }
  10. // 只在右边
  11. if (root.val < p.val && root.val < q.val) {
  12. return lowestCommonAncestor(root.right, p, q);
  13. }
  14. return root;
  15. }
  16. }

98. 验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:

节点的左子树只包含小于当前节点的数。 节点的右子树只包含大于当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。

  1. class Solution {
  2. public boolean isValidBST(TreeNode root) {
  3. if (root == null) {
  4. return true;
  5. }
  6. return dfs(root, null, null);
  7. }
  8. private boolean dfs(TreeNode node, Integer min, Integer max) {
  9. if (node == null) {
  10. return true;
  11. }
  12. if (min != null && node.val <= min) {
  13. return false;
  14. }
  15. if (max != null && node.val >= max) {
  16. return false;
  17. }
  18. return dfs(node.left, min, node.val) && dfs(node.right, node.val, max);
  19. }
  20. }

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

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

思路:
采用分而治之的策略,利用了归并排序的思想。

  1. class Solution {
  2. public TreeNode sortedArrayToBST(int[] nums) {
  3. return sAToBST(nums, 0, nums.length - 1);
  4. }
  5. public TreeNode sAToBST(int[] nums, int left, int right){
  6. if(left > right) return null;
  7. int mid = left + (right - left + 1)/2;
  8. TreeNode cur = new TreeNode(nums[mid]);
  9. cur.left = sAToBST(nums, left, mid - 1);
  10. cur.right = sAToBST(nums, mid + 1, right);
  11. return cur;
  12. }
  13. }

230. 二叉搜索树中第K小的元素

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。
说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。

思路:
中序遍历。借助 ArrayList 存放遍历到的元素,也可以声明一个成员变量进行计数。

  1. class Solution {
  2. public int kthSmallest(TreeNode root, int k) {
  3. ArrayList<Integer> res = new ArrayList<>();
  4. helper(root, res);
  5. return res.get(k-1);
  6. }
  7. public void helper(TreeNode node, ArrayList<Integer> res) {
  8. if(node == null) return;
  9. if(node.left != null) {
  10. helper(node.left, res);
  11. }
  12. res.add(node.val);
  13. if(node.right != null) {
  14. helper(node.right, res);
  15. }
  16. }
  17. }

练习:

173. 二叉搜索树迭代器

450. 删除二叉搜索树中的节点


剑指 Offer

剑指 Offer 33. 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

思路:
递归。
判断后序遍历.png

  1. class Solution {
  2. public boolean verifyPostorder(int[] postorder) {
  3. return helper(postorder, 0, postorder.length - 1);
  4. }
  5. private boolean helper(int[] postorder, int i, int j) {
  6. if (i >= j) {
  7. return true;
  8. }
  9. int p = i;
  10. while (postorder[p] < postorder[j]) {
  11. p++;
  12. }
  13. int m = p;
  14. while (postorder[p] > postorder[j]) {
  15. p++;
  16. }
  17. return p == j && helper(postorder, i, m - 1) && helper(postorder, m, j - 1);
  18. }
  19. }

剑指 Offer 36. 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

思路:
深度优先搜索。

  1. /*
  2. // Definition for a Node.
  3. class Node {
  4. public int val;
  5. public Node left;
  6. public Node right;
  7. public Node() {}
  8. public Node(int _val) {
  9. val = _val;
  10. }
  11. public Node(int _val,Node _left,Node _right) {
  12. val = _val;
  13. left = _left;
  14. right = _right;
  15. }
  16. };
  17. */
  18. class Solution {
  19. Node pre = null, head = null; //pre记录上一个节点,head为最后返回的头结点
  20. public Node treeToDoublyList(Node root) {
  21. if(root == null) return root;
  22. helper(root); //得到一个双向链表,head指向头结点
  23. head.left = pre;
  24. pre.right = head; //形成循环链表
  25. return head;
  26. }
  27. public void helper(Node root){
  28. if(root == null) return; //到了最后的时候,就返回
  29. helper(root.left); //规整左子树
  30. root.left = pre;
  31. if(pre != null){
  32. pre.right = root; //当前面还有节点的时候,连接上
  33. }
  34. else
  35. head = root; //如果前面没有节点了,证明是头结点,就更新head
  36. pre = root; //root可以视为一个节点了
  37. helper(root.right); //规整右子树
  38. }
  39. }

剑指 Offer 54. 二叉搜索树的第k大节点

给定一棵二叉搜索树,请找出其中第k大的节点。

思路:
中序遍历。
执行用时:1 ms, 在所有 Java 提交中击败了46.67%的用户
内存消耗:40.4 MB, 在所有 Java 提交中击败了100.00%的用户

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. class Solution {
  11. public int kthLargest(TreeNode root, int k) {
  12. List<Integer> list = new ArrayList<>();
  13. dfs(list, root);
  14. return list.get(list.size() - k);
  15. }
  16. private void dfs(List<Integer> list, TreeNode root) {
  17. if (root.left != null) {
  18. dfs(list, root.left);
  19. }
  20. list.add(root.val);
  21. if (root.right != null) {
  22. dfs(list, root.right);
  23. }
  24. }
  25. }

思路2:
中序遍历,提前返回。

class Solution {
    private int res, n;

    public int kthLargest(TreeNode root, int k) {
       n = k;
       dfs(root);
       return res;
    }

    public void dfs(TreeNode node) {
        if (node == null || n <= 0) return;
        dfs(node.right);
        if (--n == 0) {
            res = node.val;
            return;
        }
        dfs(node.left);
    }
}

思路3:
非中序遍历。
先得出右子树的节点个数,如果恰好等于k-1,则说明该节点为第k大的节点;
如果右子树节点个数大于k-1则继续搜索右子树第k大节点;
如果右子树节点个数小于k-1,则搜索左子树中第k-numright-1大的节点。

class Solution {
    public int kthLargest(TreeNode root, int k) {
        int numright= nodeNum(root.right);
        if( numright==k-1) return root.val;
        else if(numright>k-1) return kthLargest(root.right,k);
        else return kthLargest(root.left,k-numright-1);
    }
    private static int nodeNum(TreeNode root){
        if(root == null) return 0;
        else return 1+nodeNum(root.left)+nodeNum(root.right);
    }
}

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

思路:
递归。
执行用时:7 ms, 在所有 Java 提交中击败了42.56%的用户
内存消耗:41.2 MB, 在所有 Java 提交中击败了100.00%的用户

/**
 * 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;
        }

        // 只在左边
        if (root.val > p.val && root.val > q.val) {
            return lowestCommonAncestor(root.left, p, q);
        }

        // 只在右边
        if (root.val < p.val && root.val < q.val) {
            return lowestCommonAncestor(root.right, p, q);
        }
        return root;   
    }
}