day10

day10

515. 在每个树行中找最大值

力扣题目链接

题目

给定一棵二叉树的根节点 root,请找出该二叉树中每一层的最大值。

示例1:

Untitled

输入: root = [1,3,2,5,3,null,9]
输出: [1,3,9]

示例2:

输入: root = [1,2,3]
输出: [1,3]

提示:

二叉树的节点个数的范围是 [0,10^4]
-2^31 <= Node.val <= 2^31 - 1

思路

层序遍历,取每一层的最大值

代码实现

/**
 * https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/
 *
 * @author xiexu
 * @create 2022-03-09 11:15 AM
 */
public class _515_在每个树行中找最大值 {

    public List<Integer> largestValues(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        if (root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            int n = queue.size();
            ArrayList<Integer> list = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                TreeNode node = queue.poll();
                list.add(node.val);
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
            res.add(Collections.max(list));
        }
        return res;
    }

}

116. 填充每个节点的下一个右侧节点指针

力扣题目链接

题目

给定一个 完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

示例 1:

Untitled

输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,'#' 标志着每一层的结束。

示例 2:

输入:root = []
输出:[]

提示:

树中节点的数量在 [0, 2^12 - 1] 范围内
-1000 <= node.val <= 1000

思路

本题依然是层序遍历,只不过在单层遍历的时候记录一下本层的头部节点,然后在遍历的时候让前一个节点指向本节点就可以了

代码实现

/**
 * https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
 *
 * @author xiexu
 * @create 2022-03-09 11:25 AM
 */
public class _116_填充每个节点的下一个右侧节点指针 {

    public Node connect(Node root) {
        Queue<Node> queue = new LinkedList<>();
        if (root != null) {
            queue.add(root);
        }
        while (!queue.isEmpty()) {
            int n = queue.size();
            Node node = null;
            Node preNode = null; // 头结点

            for (int i = 0; i < n; i++) {
                if (i == 0) {
                    preNode = queue.poll(); // 取出本层头一个节点
                    node = preNode;
                } else {
                    node = queue.poll();
                    preNode.next = node;
                    preNode = preNode.next;
                }

                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
            preNode.next = null; // 本层最后一个节点 next 指向 null
        }
        return root;
    }
}

117. 填充每个节点的下一个右侧节点指针 II

力扣题目链接

题目

给定一个二叉树

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

示例:

Untitled

输入:root = [1,2,3,4,5,null,7]
输出:[1,#,2,3,#,4,5,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化输出按层序遍历顺序(由 next 指针连接),'#' 表示每层的末尾。

代码实现

/**
 * https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/
 *
 * @author xiexu
 * @create 2022-03-09 11:40 AM
 */
public class _117_填充每个节点的下一个右侧节点指针_II {

    public Node connect(Node root) {
        Queue<Node> queue = new LinkedList<>();
        if (root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            int n = queue.size();
            Node node = null;
            Node preNode = null; // 头结点
            for (int i = 0; i < n; i++) {
                if (i == 0) {
                    preNode = queue.poll(); // 取出本层头一个节点
                    node = preNode;
                } else {
                    node = queue.poll();
                    preNode.next = node;
                    preNode = preNode.next;
                }

                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
            preNode.next = null; // 本层最后一个节点 next 指向 null
        }
        return root;
    }

}

104. 二叉树的最大深度

力扣题目链接

题目

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7]

		3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

思路

使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。

在二叉树中,一层一层的来遍历二叉树,记录一下遍历的层数就是二叉树的深度,如图所示:

Untitled

代码实现

/**
 * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
 *
 * @author xiexu
 * @create 2022-03-09 12:34 PM
 */
public class _104_二叉树的最大深度 {

    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        // 深度计数
        int depth = 0;
        queue.offer(root);
        while (!queue.isEmpty()) {
            int n = queue.size();
            while (n > 0) {
                TreeNode node = queue.poll();
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
                n--;
            }
            depth++;
        }
        return depth;
    }

}

111. 二叉树的最小深度

力扣题目链接

题目

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

**说明:**叶子节点是指没有子节点的节点。

示例 1:

Untitled

输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:

输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

提示:

树中节点数的范围在 [0, 10^5]-1000 <= Node.val <= 1000

思路

需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点

代码实现

/**
 * https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
 *
 * @author xiexu
 * @create 2022-03-09 12:41 PM
 */
public class _111_二叉树的最小深度 {

    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        // 最小深度
        int depth = 0;
        queue.offer(root);
        while (!queue.isEmpty()) {
            int n = queue.size();
            depth++;
            for (int i = 0; i < n; i++) {
                TreeNode node = queue.poll();
                // 如果当前节点的左右孩子都为空,直接返回最小深度
                if (node.left == null && node.right == null) {
                    return depth;
                }

                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
        }
        return depth;
    }

}

226. 翻转二叉树

力扣题目链接

题目

给你一棵二叉树的根节点 root,翻转这棵二叉树,并返回其根节点。

示例 1:

Untitled

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例 2:

Untitled

输入:root = [2,1,3]
输出:[2,3,1]

示例 3:

输入:root = []
输出:[]

提示:

树中节点数目范围在 [0, 100]-100 <= Node.val <= 100

递归解法

思路

https://pic.leetcode-cn.com/0f91f7cbf5740de86e881eb7427c6c3993f4eca3624ca275d71e21c5e3e2c550-226_2.gif

其实就是交换一下左右节点,然后再递归的交换左节点,右节点

根据动画图我们可以总结出递归的两个条件如下:

  • 终止条件:当前节点为 null 时返回
  • 交换当前节点的左右节点,再递归的交换当前节点的左节点,递归的交换当前节点的右节点

代码实现

/**
 * https://leetcode-cn.com/problems/invert-binary-tree/
 *
 * @author xiexu
 * @create 2022-03-09 1:19 PM
 */
public class _226_翻转二叉树 {

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

}

迭代解法

思路

递归实现也就是深度优先遍历的方式,那么对应的就是广度优先遍历。
广度优先遍历需要额外的数据结构 — 队列,来存放临时遍历到的元素。
深度优先遍历的特点是一竿子插到底,不行了再退回来继续;而广度优先遍历的特点是层层扫荡。
所以,我们需要先将根节点放入到队列中,然后不断的迭代队列中的元素。
对当前元素调换其左右子树的位置,然后:

  • 判断其左子树是否为空,不为空就放入队列中
  • 判断其右子树是否为空,不为空就放入队列中

https://pic.leetcode-cn.com/f9e06159617cbf8372b544daee37be70286c3d9b762c016664e225044fc4d479-226_%E8%BF%AD%E4%BB%A3.gif

代码实现

/**
 * https://leetcode-cn.com/problems/invert-binary-tree/
 *
 * @author xiexu
 * @create 2022-03-09 3:24 PM
 */
public class _226_翻转二叉树_迭代 {

    public TreeNode invertTree(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        if (root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            int n = queue.size();
            for (int i = 0; i < n; i++) {
                // 每次都从队列中拿一个节点,并交换这个节点的左右子树
                TreeNode node = queue.poll();
                TreeNode temp = node.left;
                node.left = node.right;
                node.right = temp;

                // 如果当前节点的左子树不为空,则放入队列等待后续处理
                if (node.left != null) {
                    queue.offer(node.left);
                }
                // 如果当前节点的右子树不为空,则放入队列等待后续处理
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
        }
        return root;
    }

}

101. 对称二叉树

力扣题目链接

题目

给你一个二叉树的根节点 root, 检查它是否轴对称。

示例 1:

Untitled

输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

Untitled

输入:root = [1,2,2,null,3,null,3]
输出:false

提示:

树中节点数目在范围 [1, 1000]-100 <= Node.val <= 100

递归解法

思路

我们将根节点的左子树记做 left,右子树记做 right。比较 left是否等于 right,不等的话直接返回就可以了。

如果相等,比较 left的左节点和 right的右节点,再比较 left的右节点和 right的左节点

比如看下面这两个子树(他们分别是根节点的左子树和右子树),能观察到这么一个规律:

		2         2
   / \       / \
  3   4     4   3
 / \ / \   / \ / \
8  7 6  5 5  6 7  8
  • 左子树 2 的左孩子 == 右子树 2 的右孩子
  • 左子树 2 的右孩子 == 右子树 2 的左孩子

终止条件:

  • left 和 right 不等,或者 left 和 right 都为空
  • 递归的比较 left.leftright.right,递归比较 left.rightright.left

https://pic.leetcode-cn.com/2449af8862537df2cbbc45a07764415c1a10769677c822fa271ea7447c8fa128-2.gif

代码实现

/**
 * https://leetcode-cn.com/problems/symmetric-tree/
 *
 * @author xiexu
 * @create 2022-03-09 3:39 PM
 */
public class _101_对称二叉树 {

    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        // 调用递归函数,比较左节点、右节点
        return dfs(root.left, root.right);
    }

    public boolean dfs(TreeNode left, TreeNode right) {
        // 递归的终止条件是两个节点都为空
        // 或者两个节点中有一个为空
        // 或者两个节点的值不相等
        if (left == null && right == null) {
            return true;
        }
        if (left == null || right == null) {
            return false;
        }
        if (left.val != right.val) {
            return false;
        }
        // 再递归的比较 左节点的左孩子 和 右节点的右孩子
        // 以及比较 左节点的右孩子 和 右节点的左孩子
        return dfs(left.left, right.right) && dfs(left.right, right.left);
    }

}

迭代解法

思路

  • 首先从队列中拿出两个节点(leftright)比较
  • leftleft 节点和 rightright 节点放入队列
  • leftright 节点和 rightleft 节点放入队列

https://pic.leetcode-cn.com/45a663b08efaa14193d63ef63ae3d1d130807467d13707f584906ad3af4adc36-1.gif

代码实现

/**
 * https://leetcode-cn.com/problems/symmetric-tree/
 *
 * @author xiexu
 * @create 2022-03-09 4:12 PM
 */
public class _101_对称二叉树_迭代 {

    public boolean isSymmetric(TreeNode root) {
        if (root == null || (root.left == null && root.right == null)) {
            return true;
        }
        // 用队列保存节点
        Queue<TreeNode> queue = new LinkedList<>();
        // 将根节点的左右孩子放到队列中
        queue.offer(root.left);
        queue.offer(root.right);

        while (!queue.isEmpty()) {
            // 从队列中取出两个节点,再比较这两个节点
            TreeNode left = queue.poll();
            TreeNode right = queue.poll();
            // 如果两个节点都为空就继续循环,两者有一个为空就返回false
            if (left == null && right == null) {
                continue;
            }
            if (left == null || right == null) {
                return false;
            }
            if (left.val != right.val) {
                return false;
            }

            // 将左节点的左孩子,右节点的右孩子放入队列
            queue.add(left.left);
            queue.add(right.right);
            // 将左节点的右孩子,右节点的左孩子放入队列
            queue.add(left.right);
            queue.add(right.left);
        }
        return true;
    }

}

100. 相同的树

力扣题目链接

题目

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:

Untitled

输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2:

Untitled

输入:p = [1,2], q = [1,null,2]
输出:false

示例 3:

Untitled

输入:p = [1,2,1], q = [1,1,2]
输出:false

提示:

两棵树上的节点数目都在范围 [0, 100]-10^4 <= Node.val <= 10^4

思路

终止条件与返回值:

  • 当两棵树的当前节点都为 null 时返回 true
  • 当其中一个为 null 另一个不为 null 时返回 false
  • 当两个都不为空但是值不相等时,返回 false

代码实现

/**
 * https://leetcode-cn.com/problems/same-tree/
 *
 * @author xiexu
 * @create 2022-03-09 4:27 PM
 */
public class _100_相同的树 {

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

}

572. 另一棵树的子树

力扣题目链接

题目

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

示例 1:

Untitled

输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true

示例 2:

Untitled

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false

提示:

root 树上的节点数量范围是 [1, 2000]
subRoot 树上的节点数量范围是 [1, 1000]
-10^4 <= root.val <= 10^4
-10^4 <= subRoot.val <= 10^4

代码实现

/**
 * https://leetcode-cn.com/problems/subtree-of-another-tree/
 *
 * @author xiexu
 * @create 2022-03-09 4:37 PM
 */
public class _572_另一棵树的子树 {

    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if (root == null) {
            return subRoot == null;
        }
        // 判断以 root 为根的二叉树是否和 subRoot 相同
        if (isSameTree(root, subRoot)) {
            return true;
        }
        // 去左右子树中判断是否有和 subRoot 相同的子树
        return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
    }

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

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿小羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值