20230823 | 二叉树 Part2

BFS & DFS

广度优先: 队列先进先出,符合一层一层遍历的逻辑, 迭代
深度优先: 先进后出适合模拟深度优先遍历也就是递归的逻辑 前中后序既可以递归也可迭代

十道本质一样的层序遍历

Leetcode102 Binary Tree Level Order Traversal

Method1 BFS 借助队列

Notice: 层序遍历的过程和取出queue里面的值是两个步骤, 不应搞混

  1. 先把root塞入queue, !queue.isEmpty() 用来遍历当前这一层. 在这一层里, 把queue里面的root取出并把新的左右子树放入该queue (此时该queue是为了后面的第二层). root被poll后, 此时原queue size = 0 再进入新的queue的循环
  2. 开始第二层的层序遍历, 依然用 !queue.isEmpty() 遍历当前这一层, 后续同理
class Solution {
	List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        bfs(root);
        return result;

    }
    public void bfs(TreeNode root){
        if (root == null) return;
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);

        while (!queue.isEmpty()){
            List<Integer> list = new ArrayList<>();
            int size = queue.size();
            while (size > 0){
                TreeNode node = queue.poll();
                list.add(node.val);
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
                size--;
            }
            result.add(list);
        }
   }
}

Method2 DFS 递归

class Solution {
List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        dfs(root,0);
        return result;

    }
    // Method2 DFS
    public void dfs(TreeNode root, int deep){
        if (root == null) return;
        deep++;
        // 此处用来判定需不需要添加新的List<Integer>
        if (result.size() < deep){
            List<Integer> list = new ArrayList<>();
            result.add(list);
        }
        result.get(deep-1).add(root.val);

        dfs(root.left, deep);
        dfs(root.right, deep);

    }
} 

Leetcode107 Binary Tree Level Order Traversal II

题目链接
与上题的区别在于从下往上输出了, Collections.reverse(list) 即可解决

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        bfs(root);
//        dfs(root,0);
        return result;

    }
    // Method 1: BFS 借助队列
    public void bfs(TreeNode root){
        if (root == null) return;
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);

        while (!queue.isEmpty()){
            List<Integer> list = new ArrayList<>();
            int size = queue.size();
            while (size > 0){
                TreeNode node = queue.poll();
                list.add(node.val);
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
                size--;
            }
            result.add(list);
        }
        Collections.reverse(result);
    }
}

Leetcode199 Binary Tree Right Side View

题目链接 二叉树的右视图
本题一开始写的时候误以为是只考虑右子树, 这是不对的. 而是从右往左看二叉树

class Solution {
    List<Integer> result = new ArrayList<>();
    public List<Integer> rightSideView(TreeNode root) {
        bfs(root);
        return result;
    }

    public void bfs(TreeNode root){
        if (root == null) return;
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.add(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            // 循环queue
            for (int i = 0; i < size; i++){
                TreeNode tmp = queue.poll();
                // 优先放入右子树
                if (tmp.right != null) queue.add(tmp.right);
                if (tmp.left != null) queue.add(tmp.left);
                // 如果左右子树同时存在, 那么只放第一个值
                if (i == 0) result.add(tmp.val);
            }
        }
    }
}

Leetcode637 Average of Levels in Binary Tree

题目链接 算每一层的平均值

同102, 得出每一层的所有值后求平均, 每一层的 queue.size 就是分母

class Solution {
    List<Double> result = new ArrayList<>();
    public List<Double> averageOfLevels(TreeNode root) {
        dfs(root);
        return result;
    }
    public void dfs(TreeNode root){
        if (root == null) return;
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);

        while(!queue.isEmpty()){
            double sum = 0.0;
            double size = queue.size(), num = size;
            while(size > 0){
                TreeNode tmp = queue.poll();
                sum += tmp.val;
                if (tmp.left != null) queue.offer(tmp.left);
                if (tmp.right != null) queue.offer(tmp.right);
                size--;
            }
            double average = sum / num;
            result.add(average);
        }
    }
}

Leetcode429 N-ary Tree Level Order Traversal

题目链接 二叉树改为任意个数
TreeNode改为Node, 同理. 循环子树即可

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> levelOrder(Node root) {
        bfs(root);
        return result;
    }
    public void bfs(Node root){
        if (root == null) return;
        Queue<Node> queue = new ArrayDeque<>();
        queue.offer(root);

        while(!queue.isEmpty()){
            List<Integer> med = new ArrayList<>();
            int size = queue.size();

            while (size > 0){
                Node tmp = queue.poll();
                med.add(tmp.val);
                if (tmp.children != null){
                    for (Node x: tmp.children){
                        queue.offer(x);
                    }
                }
                size--;
            }
            result.add(med);
        }
    }
}

Leetcode515 Find Largest Value in Each Tree Row

题目链接 找每一行最大值

class Solution {
    List<Integer> result = new ArrayList<>();
    public List<Integer> largestValues(TreeNode root) {
        bfs(root);
        return result;
    }
    public void bfs(TreeNode root){
        if (root == null) return;
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            int maximum = Integer.MIN_VALUE;
            while(size > 0){
                TreeNode tmp = queue.poll();
                if (tmp.val > maximum) maximum = tmp.val;
                if (tmp.left != null) queue.offer(tmp.left);
                if (tmp.right != null) queue.offer(tmp.right);
                size--;
            }
            result.add(maximum);
        }
    }
}

Leetcode116 Populating Next Right Pointers in Each Node

题目链接

Method 1

我复制了一个新的copy queue, 来确定tmp要指向哪个node

class Solution {
    public Node connect(Node root) {
        return bfs(root);
    }
    public Node bfs(Node root){
        if (root == null) return null;
        Queue<Node> queue = new ArrayDeque<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            Queue<Node> copy = new ArrayDeque<>(queue);
            for (int i = 0; i < size; i++){
                Node tmp = queue.poll();
                copy.poll();
                tmp.next = copy.peek();
                if (tmp.left != null) queue.offer(tmp.left);
                if (tmp.right != null) queue.offer(tmp.right);
            }
        }
        return root;
    }
}

Method2

代码随想录提供了一个新的思路, 即先poll最优先值, 如果queue里还有, 再poll后面的值, 确定tmp.next
可以不用管null, 因为什么都不做node就指向null

class Solution {
    public Node connect(Node root) {
        return bfs(root);
    }
    public Node bfs(Node root){
        if (root == null) return null;
        Queue<Node> queue = new ArrayDeque<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            int size = queue.size();
            Node tmp = queue.poll();
            if (tmp.left != null) queue.offer(tmp.left);
            if (tmp.right != null) queue.offer(tmp.right);
            for (int i = 1; i < size; i++){
                Node nex = queue.poll();
                if (nex.left != null) queue.offer(nex.left);
                if (nex.right != null) queue.offer(nex.right);
                tmp.next = nex;
                tmp = tmp.next;
            }
            }
        return root;
    }
}

Leetcode117 Populating Next Right Pointers in Each Node II

题目链接 填充每个节点的下一个右侧节点指针II
同116

Leetcode104 二叉树的最大深度

题目链接 二叉树的最大深度

Method1 BFS

广度优先搜索就是遍历每一层, 每一层depth++, 很合理

class Solution {
    public int maxDepth(TreeNode root) {
        return bfs(root);
    }
    public int bfs(TreeNode root){
        if (root == null) return 0;
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);
        int depth = 0;
        while (!queue.isEmpty()){
            int size = queue.size();
            depth++;
            while (size > 0){
                TreeNode tmp = queue.poll();
                if (tmp.left != null) queue.offer(tmp.left);
                if (tmp.right != null) queue.offer(tmp.right);
                size--;
            }
        }
        return depth;
    }
}

但是在这用BFS很慢

Method2 DFS

backtrack = dfs + 剪枝

class Solution {
    int depth = 0;
    int maxDepth = 0;
    public int maxDepth(TreeNode root) {
        traverse(root);
        return maxDepth;
    }

    public void traverse(TreeNode root){
        if (root == null) return;

        depth++;
        if (root.left == null && root.right == null){
            maxDepth = Math.max(maxDepth, depth);
        }
        traverse(root.left);
        traverse(root.right);
        depth--;

    }
}

Leetcode111 Minimum Depth of Binary Tree

题目链接 二叉树的最小深度

Method1 BFS

Method2 DFS

class Solution {
    int depth = 0;
    int minDepth = Integer.MAX_VALUE;
    public int minDepth(TreeNode root) {
        if (root == null){
            return 0;
        }
        dfs(root);
        return minDepth;
    }
    public void dfs(TreeNode root){
    	// 终止条件
        if (root == null) return;
        depth++;
		// 对子树操作
        dfs(root.left);
        if (root.left == null && root.right == null){
            minDepth = Math.min(depth, minDepth);
        }
        dfs(root.right);
        // 回溯
        depth--;
    }
}

Leetcode226 Invert Binary Tree

题目链接 翻转二叉树

Method1 迭代法

Method1.1 BFS
class Solution {
    public TreeNode invertTree(TreeNode root){
        bfs(root);
        return root;
    }
    public void bfs(TreeNode root){
        if (root == null) return;
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            while (size > 0){
                TreeNode tmp = queue.poll();
                if (tmp.left != null) queue.offer(tmp.left);
                if (tmp.right != null) queue.offer(tmp.right);
                // 左右交换
                TreeNode x = tmp.left;
                tmp.left = tmp.right;
                tmp.right = x;
                size--;
            }
        }
    }
}
Method1.2 DFS深度优先遍历

Method2 递归

DFS: 前序遍历
  1. 确定递归函数的参数和返回值 invertTree(TreeNode root)
  2. 确定终止条件 if (root == null) return null;
  3. 确定单层递归逻辑 左右子树交换
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;
    }

Leetcode101 Symmetric Tree

题目链接

一开始做本题时想单纯比较左右子树, 这是错误的, 实际除了root以外都无法单纯比较左右子树

        1
      /    \
     2      2
    /        \
   3          3

在第二层2的左右子树显然不一样.

Method1: 递归

该题真正需要比较的是根节点的左右子树, 即子树的内侧和外侧是否相等, 在递归时要同时遍历两棵树
左右子树

Notice: 本题的遍历方式只能是后序遍历, 我们需要在比较完左右子树之后再向上返回值, 外侧相同和内侧相同必须同时true以后, 才能告诉父类
如果用左中右, 父节点显然无法知道它的一端子树是否是对称的

后序: 收集孩子的信息, 向上一层返回值

  1. 确定函数类型和返回对象: 根节点的两个子树是否可以翻转 -> 比较左右两个树
    boolean compare(TreeNode left, TreeNode right)
  2. 确定终止条件 每一次递归完后返回什么: 比较的不是左右孩子!! 左节点和右节点
if ((left == null && right != null) || (left != null && right == null)) return false;
else if (left == null && right == null) return true;
else if (left.val != right.val) return false;
  1. 确定单层递归逻辑: 先比较外侧, 再比较内层, 最后返回到父结点
public boolean isSymmetric(TreeNode root) {
        boolean result = compare(root.left, root.right);
        return result;
    }

    public boolean compare(TreeNode left, TreeNode right){
        // 确定终止条件
        if ((left == null && right != null) || (left != null && right == null)) return false;
        else if (left == null && right == null) return true;
        else if (left.val != right.val) return false;

        boolean a = compare(left.left, right.right);
        boolean b = compare(left.right, right.left);
        return a&&b;
    }

Method2 迭代 (非bfs)

只能用Linkedlist<>构建queue, LinkedList允许element为null, ArrayDeque若子树出现null会报错, 加不进去

public boolean isSymmetric(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root.left);
        queue.offer(root.right);
        while (!queue.isEmpty()){
            TreeNode left = queue.poll();
            TreeNode right = queue.poll();
            if (left == null && right == null) continue;
            if (left == null || right == null || left.val != right.val) {
                return false;
            }
            queue.offer(left.left);
            queue.offer(right.right);
            queue.offer(left.right);
            queue.offer(right.left);
         }
        return true;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值