Skip to content

二叉树


94. 二叉树的中序遍历

java
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<Integer>();
        inOrder(root, ans);
        return ans;
    }

    public void inOrder(TreeNode root, List<Integer> ans) {
        if (root == null) return;
        inOrder(root.left, ans);
        ans.add(root.val);
        inOrder(root.right, ans);
    }
}

104. 二叉树的最大深度

java
class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) return 0;
        return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
    }
}

226. 翻转二叉树

java
// 直接交换节点左右孩子,和官解不同
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return null;
        }
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

101. 对称二叉树

java
class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isSame(root.left, root.right);
    }

    public boolean isSame(TreeNode left, TreeNode right) {
        if (left == null && right == null) return true;
        if (left == null && right != null) return false;
        if (left != null && right == null) return false;
        if (left.val != right.val) return false;
        return isSame(left.left, right.right) && isSame(left.right, right.left);
    }
}

543. 二叉树的直径

java
// 先按照计算树的高度思路写,左右子树的高度用l, r表示,遍历每个节点的时候更新ans即可
class Solution {
    private int ans;

    public int diameterOfBinaryTree(TreeNode root) {
        height(root);
        return ans;
    }

    public int height(TreeNode root) {
        if (root == null) return 0;
        int l = height(root.left);
        int r = height(root.right);
        ans = Math.max(ans, l + r);
        return 1 + Math.max(l, r);
    }
}

102. 二叉树的层序遍历

java
// 借助队列,BFS
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ans = new ArrayList<>();
        if (root == null) return ans;

        Queue<TreeNode> que = new ArrayDeque<>();
        que.offer(root);
        while (!que.isEmpty()) {
            int size = que.size();
            List<Integer> layer = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                TreeNode node = que.poll();
                layer.add(node.val);
                if (node.left != null) que.offer(node.left);
                if (node.right != null) que.offer(node.right);
            }
            ans.add(layer);
        }
        return ans;
    }
}

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

java
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return BST(nums, 0, nums.length - 1);
    }

    public TreeNode BST(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }
        int mid = (left + right) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = BST(nums, left, mid - 1);
        root.right = BST(nums, mid + 1, right);
        return root;
    }
}

98. 验证二叉搜索树

java
// 作者:灵茶山艾府
// 本质还是中序遍历,如果判断左边,再判断根,最后判断右边
class Solution {
    private long pre = Long.MIN_VALUE;

    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        if (!isValidBST(root.left) || pre >= root.val) {
            return false;
        }
        pre = root.val;
        return isValidBST(root.right);
    }
}

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

java
// 方法一:二叉搜索树中序遍历到第k个节点即可,这里用递归全部遍历了,最佳解还是用栈循环迭代
class Solution {
    private int cnt;
    private int ans;

    public int kthSmallest(TreeNode root, int k) {
        inOrder(root, k);
        return ans;
    }

    public void inOrder(TreeNode root, int k) {
        if (root == null) {
            return;
        }
        inOrder(root.left, k);
        if (++cnt == k) {
            ans = root.val;
        }
        inOrder(root.right, k);
    }
}

// 方法二:利用栈进行迭代,不需要根先入栈,两个while循环一直添加左孩子
class Solution {
    public int kthSmallest(TreeNode root, int k) {
        Deque<TreeNode> stack = new ArrayDeque<>();

        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
        // 出栈,然后root指向右孩子
            root = stack.pop();
            if (--k == 0) {
                break;
            }
            root = root.right;
        }

        return root.val;
    }
}

199. 二叉树的右视图

java
// 方法一:借助队列进行迭代,每层最后一个即为ans
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        if (root == null) return ans;
        // 栈用Deque, 队列用Queue, 都new ArrayDeque
        Queue<TreeNode> que = new ArrayDeque<>();
        que.offer(root);
        while (!que.isEmpty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode node = que.poll();
                if (node.left != null) que.offer(node.left);
                if (node.right != null) que.offer(node.right);
                if (i == size - 1) ans.add(node.val);
            }
        }
        return ans;
    }
}

// 方法二:灵神的递归,根右左的先序遍历,根据往下的深度以及ans的当前size进行填充
class Solution {
    List<Integer> ans = new ArrayList<>();

    public List<Integer> rightSideView(TreeNode root) {
        dfs(root, 0);
        return ans;
    }

    public void dfs(TreeNode root, int depth) {
        if (root == null) return;
        if (depth == ans.size()) {
            ans.add(root.val);
        }
        dfs(root.right, depth + 1);
        dfs(root.left, depth + 1);
    }
}

114. 二叉树展开为链表

java
// 展开为链表就想象成一行,更新next即可

// 方法一:定义一个链表的虚拟头节点,先序遍历
// 需要临时变量temp记录当前节点的右孩子,使得先序遍历正常进行,否则右孩子丢失
public class Solution {
    private TreeNode dummy = new TreeNode();

    public void flatten(TreeNode root) {
        if (root == null) {
            return;
        }
        TreeNode temp = root.right;

        dummy.right = root;// 此处修改了上一层的节点右指针,会导致原有的右孩子找不到,因此temp先记录,按照先序正常遍历
        dummy = root;
        flatten(root.left);
        flatten(temp);
        root.left = null;
    }
}

// 方法二: 右,左,根,因此建立的链表是从末尾向前
// 作者:一半王二,一半三毛
public class Solution {
    TreeNode tail = null;
    public void flatten(TreeNode root){
        if(root == null) return;
        flatten(root.right);
        flatten(root.left);
        root.left = null;
        root.right = tail;
        tail = root;
    }
}

105. 从前序与中序遍历序列构造二叉树

java
// inorder的划分比较好确定,而前序分别可以获取头尾,剩下两个计算即可
class Solution {
    private Map<Integer, Integer> mp = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for (int i = 0; i < inorder.length; i++) {
            mp.put(inorder[i], i);
        }
        return build(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
    }

    public TreeNode build(int[] preorder, int[] inorder, int m, int n, int x, int y) {
        if (m > n)
            return null;
        TreeNode root = new TreeNode(preorder[m]);
        int idx = mp.get(preorder[m]);
        root.left = build(preorder, inorder, m + 1, m - x + idx, x, idx - 1);
        root.right = build(preorder, inorder, n + idx + 1 - y, n, idx + 1, y);
        return root;
    }
}

437. 路径总和 III

java
// 哈希,前缀和,深度优先,最后返回父节点回溯
// 注意超出范围,和的部分需要Long,数字后面加L
class Solution {
    private int ans;
    private Map<Long, Integer> map = new HashMap<>();

    public int pathSum(TreeNode root, int targetSum) {
        map.put(0L, 1);
        dfs(root, targetSum, 0L);
        return ans;
    }

    public void dfs(TreeNode root, int targetSum, long curSum) {
        if (root == null) {
            return;
        }
        curSum += root.val;
        ans += map.getOrDefault(curSum - targetSum, 0);
        map.put(curSum, map.getOrDefault(curSum, 0) + 1);

        dfs(root.left, targetSum, curSum);
        dfs(root.right, targetSum, curSum);

        // 返回父节点需要回溯
        if (map.put(curSum, map.get(curSum) - 1) == 1) {
            map.remove(curSum);
        }
    }
}

236. 二叉树的最近公共祖先

java
// 看灵神,分情况
// 如果p或者q就是根直接返回根
// 否则去左子树找,然后去右子树找,这里是找到其一就有返回值,因此如果左右各在一边结果非空,返回根节点
// 只有一个有返回值
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 && right != null) {    // 在左右子数中都有返回结果,说明p, q各在一边
            return root;
        }
        return left != null ? left : right;
    }
}