力扣hot100-二叉树

概要

二叉树(Binary Tree)是一种树形数据结构,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树在算法和计算机科学中具有广泛的应用,特别是在表达式解析、搜索算法、排序算法、优先级队列、堆和其他数据结构中。

二叉树的基本概念

  1. 节点 (Node):二叉树中的每个元素。
  2. 根节点 (Root Node):二叉树的顶端节点。
  3. 叶节点 (Leaf Node):没有子节点的节点。
  4. 子节点 (Child Node):某节点的直接后继。
  5. 父节点 (Parent Node):某节点的直接前驱。
  6. 高度 (Height):从根节点到叶节点的最长路径上的节点数。
  7. 深度 (Depth):从根节点到某节点的路径上的节点数。
  8. 层次 (Level):从根节点开始,第 1 层为根节点,其子节点为第 2 层,以此类推。

常见的二叉树类型

  1. 完全二叉树 (Complete Binary Tree):除了最后一层,其他每一层的节点都达到最大数,最后一层的节点全部集中在最左边。
  2. 满二叉树 (Full Binary Tree):每个节点要么是叶子节点,要么有两个子节点。
  3. 二叉搜索树 (Binary Search Tree, BST):对于树中的每个节点,其左子树的所有节点值小于该节点值,右子树的所有节点值大于该节点值。
  4. 平衡二叉树 (Balanced Binary Tree):左右子树的高度差不超过 1。

常用的二叉树遍历

  1. 前序遍历 (Pre-order Traversal):根节点 -> 左子树 -> 右子树。
  2. 中序遍历 (In-order Traversal):左子树 -> 根节点 -> 右子树。
  3. 后序遍历 (Post-order Traversal):左子树 -> 右子树 -> 根节点。
  4. 层次遍历 (Level-order Traversal):按层次从上到下、从左到右遍历。

二叉树的常用技巧

  1. 递归

    • 许多二叉树问题可以通过递归来解决,因为二叉树的结构天然适合递归思想。
    • 例如,求二叉树的高度可以通过递归求左右子树的高度,然后取最大值加一。
  2. 迭代

    • 使用栈或队列来模拟递归过程,实现非递归的遍历方法。
    • 例如,中序遍历可以通过显式栈来实现。
  3. 回溯

    • 回溯法常用于在树中寻找路径或解决路径问题。
    • 例如,在路径和为某一值的情况下,回溯法可以在遍历的过程中动态构建路径并回退。
  4. 动态规划

    • 在处理一些优化问题时,可以在二叉树上应用动态规划,通过存储子问题的结果来减少重复计算。
    • 例如,在二叉树上查找最长路径等问题中。
  5. 分治法

    • 将问题分解为若干子问题分别解决,然后合并子问题的结果。
    • 例如,合并两棵二叉树、构造平衡二叉树等。

题目:二叉树的中序遍历

原题链接:二叉树的中序遍历
在这里插入图片描述

方法1–递归遍历

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

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

方法2–使用栈

栈(Stack):利用栈来模拟递归的行为。栈在遍历左子树时保存节点,确保能够回到父节点,并遍历右子树。

对于二叉树的中序遍历,访问节点的顺序是:左子树 -> 根节点 -> 右子树。代码的关键在于使用了一个来模拟递归调用的过程。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        LinkedList<TreeNode> stack = new LinkedList<>();
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            list.add(root.val);
            root = root.right;
        }
        return list;
    }
}

题目 二叉树的最大深度

原题链接: 二叉树的最大深度

在这里插入图片描述

题解

用递归!

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

题目:翻转二叉树

原题链接:翻转二叉树

在这里插入图片描述

方法1–递归

从下到上

 public TreeNode invertTree(TreeNode root) {
        // 如果当前节点为空,直接返回空
        if (root == null) {
            return null;
        }

        // 递归翻转左右子树
        TreeNode left = invertTree(root.left);
        TreeNode right = invertTree(root.right);

        // 交换左右子树
        root.left = right;
        root.right = left;

        // 返回当前节点
        return root;
    }

从上到下

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

方法2–非递归

不用递归,用迭代的方法,通常使用栈或队列来模拟递归的调用栈

public TreeNode invertTree(TreeNode root) {
    if (root == null) return null;

    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);

    while (!queue.isEmpty()) {
        TreeNode current = queue.poll();

        // 交换左右子节点
        TreeNode temp = current.left;
        current.left = current.right;
        current.right = temp;

        // 将子节点加入队列以处理它们的子节点
        if (current.left != null) queue.offer(current.left);
        if (current.right != null) queue.offer(current.right);
    }

    return root;
}

题目

原题链接: 对称二叉树
在这里插入图片描述

题解

   public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        return isMirror(root.left, root.right);
    }

    private boolean isMirror(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        }
        if (left == null || right == null) {
            return false;//不对称
        }
        return (left.val == right.val)
                && isMirror(left.left, right.right)
                && isMirror(left.right, right.left);
    }
  • 左子树的左子节点 left.left 与右子树的右子节点 right.right 要镜像对称。
  • 左子树的右子节点 left.right 与右子树的左子节点 right.left 要镜像对称。

left.val == right.val:2 == 2,满足。
isMirror(left.left, right.right):即 3 与 3,满足。
isMirror(left.right, right.left):即 4 与 4,满足。

    1
   / \
  2   2
 / \ / \
3  4 4  3

题目:二叉树的直径

原题链接:二叉树的直径

在这里插入图片描述

题解

方法:分解问题

最大深度的计算:

  • 二叉树的直径可以通过计算每个节点的左右子树的最大深度来获得。
  • 对于每个节点,计算其左子树和右子树的深度。
  • 节点的直径等于左子树深度加右子树深度。
public class T543 {
    private int res = 0;

    public int diameterOfBinaryTree(TreeNode root) {
        depth(root);
        return res;
    }

    private int depth(TreeNode node) {
        if (node == null) {
            return 0;
        }

        int left = depth(node.left);
        int right = depth(node.right);

        // 计算经过当前节点的直径
        res = Math.max(res, left + right);

        // 返回当前节点的深度
        return Math.max(left, right) + 1;
    }
}

···


其实这道题和`二叉树的最大深度`有很大关系的,我们看看`二叉树的最大深度`代码
```java
   public int maxDepth(TreeNode root) {
        if (root == null) return 0;
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        // 
        return Math.max(left, right) + 1;
    }

在上面源码中的//那里添加动态更新最大路径就是本道题的答案。

二叉树的直径这个题,针对一个节点,我需要把左子树,右子树深度都计算出来,然后动态更新直径,所以在后序位置更新直径。

题目:二叉树的层序遍历

原题链接:二叉树的层序遍历

在这里插入图片描述

题解

方法:借助队列这个数据结构

    public static List<List<Integer>> levelOrder(TreeNode root) {
        ArrayList<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);

        while (!queue.isEmpty()) {
            int size = queue.size();
            ArrayList<Integer> temp = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
                temp.add(node.val);
            }
            res.add(temp);
        }
        return res;
    }

在while循环的每次迭代开始时,queue存储的是当前层的所有节点。

题目:将有序数组转换为二又搜索树

原题链接:将有序数组转换为二又搜索树
在这里插入图片描述

题解

将有序数组转换为二叉搜索树的关键在于利用数组的中间元素作为树的根节点,然后递归地对左右子数组执行相同的操作,构建左右子树

 public static TreeNode sortedArrayToBST(int[] nums) {
        return convertToBST(nums, 0, nums.length - 1);
    }

    private static TreeNode convertToBST(int[] nums, int left, int right) {
        if (left > right) return null;
        int mid = (left + right) / 2;
        TreeNode node = new TreeNode(nums[mid]);
        node.left = convertToBST(nums, left, mid - 1);
        node.right = convertToBST(nums, mid + 1, right);
        return node;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值