BFS解题日记之树相关(一)

145 阅读1分钟

对称的二叉树

什么是对称二叉树

根据题目的描述,我们先翻译一下什么是对称二叉树。

  • 根节点的左右节点都不为空,且值相同
  • 左右子节点的子节点不能只有一个存在,一个为空
  • 左子节点的左子节点值 = 右子节点的右子节点值
  • 左子节点的右子节点值 = 右子节点的左子节点值
  • 如果左子节点的左子节点为空,那么右子节点也一定为空

这种遍历子节点的题目,我们可以使用bfs广度优先借用队列这种数据结构来做。我们只需要按照上述比较的顺序进行保存到队列中,依靠队列先进先出的特性进行比较就可以了。

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root.left);
        q.offer(root.right);

        while (!q.isEmpty()) {
            TreeNode left = q.poll();
            TreeNode right = q.poll();

            if (left == null && right == null) continue;
            if (left == null || right == null) return false;
            if (left.val != right.val) return false;

            q.offer(left.left);
            q.offer(right.right);

            q.offer(left.right);
            q.offer(right.left);
        }

        return true;
    }
}

二叉树层序遍历

借助队列实现层序遍历

class Solution {

    private List<List<Integer>> res = new ArrayList<>();

    public List<List<Integer>> levelOrder(TreeNode root) {
        if (root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

        while (!q.isEmpty()) {
            //当前队列的长度,也就是该层的长度
            //因为for循环能队列的长度会随之变化,所以需要size常量,先确定当前层的长度。
            int size = q.size();
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                root = q.poll();
                list.add(root.val);

                if (root.left != null) q.offer(root.left);
                if (root.right != null) q.offer(root.right);
            }

            res.add(list);
        }

        return res;
    }
}

二叉树的层级遍历(层倒序)

这道题只需要在层序遍历的基础上,增加一个技巧,将遍历的层数据放在队列尾部,这样就可以实现将层是倒序输出的。

class Solution {

    private List<List<Integer>> res = new ArrayList<>();
    
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        if (root == null) return res;
        
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

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

            for (int i = 0; i< size; i++) {
                root = q.poll();
                list.add(root.val);

                if (root.left != null) q.offer(root.left);
                if (root.right != null) q.offer(root.right);
            }
            
            //核心代码,将结果放在队列尾部
            res.add(0, list);
        }

       return res;
    }

}

二叉树的锯齿遍历

解题思路

锯齿型实际上就是蛇形遍历,从左到右,再从右到走,依次到层级结束。 这里可以直接使用队列这种数据结构,使用一个标记位,当标记位是true的时候,我们倒序遍历,反之,我们正序遍历。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {

    private List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        if (root == null) return res;
        boolean flag = false;
        
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

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

            for (int i = 0; i < size; i++) {
                root = q.poll();
                if (flag) {
                    list.add(0, root.val);
                } else {
                    list.add(root.val);
                }

                if (root.left != null) q.offer(root.left);
                if (root.right != null) q.offer(root.right);
            }

            flag = !flag;
            res.add(list);
        }

        return res;
    }
}

二叉树最小深度

解题思路

BFS可以解决常见的最小、最短、最快等问题。因为bfs是按层遍历的,当遇到节点满足判断条件,就可以反馈。 最小深度也就意味着,有节点左&右节点同时为空,我们只需要使用bfs遍历模板增加对此条件的判断就可以了。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) return 0;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        int depth = 0;

        while (!q.isEmpty()) {
            int size = q.size();
            depth++;

            for (int i = 0; i < size; i++) {
                root = q.poll();
                if (root.left == null && root.right == null) return depth;

                if (root.left != null) q.offer(root.left);
                if (root.right != null) q.offer(root.right);
            }
        }

        return depth;
    }
}

二叉树的右视图

解题思路

BFS模板题,右视图实际上就是每层的最后一个,左视图就是每层的第一个。 使用 i == size - 1,这种判断条件就可以解决这个问题。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        if (root == null) return new ArrayList<>();
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

        List<Integer> res = new ArrayList<>();

        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                root = q.poll();
                if (i == size - 1) {
                    res.add(root.val);
                }

                if (root.left != null) q.offer(root.left);
                if (root.right != null) q.offer(root.right);
            }
        }

        return res;
    }
}

二叉树每行的最大值

解题思路

标准层次遍历题,初始化一个最大值(Integer的最小值) 层序遍历更新每层的最大值,层次遍历结束后重置最大值

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> largestValues(TreeNode root) {
        if (root == null) return new ArrayList<>();
        List<Integer> res = new ArrayList<>();

        int maxValue = Integer.MIN_VALUE;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                root = q.poll();
                if (root.val > maxValue) {
                    maxValue = root.val;
                }

                if (root.left != null) q.offer(root.left);
                if (root.right != null) q.offer(root.right);
            }

            res.add(maxValue);
            maxValue = Integer.MIN_VALUE;
        }

        return res;
    }
}

N叉树的最大深度

解题思路

可以使用bfs模板解决,按层级记录深度,遍历完成后深度就是最大的深度。

代码

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
    public int maxDepth(Node root) {
        if (root == null) return 0;
        int depth = 0;
        Queue<Node> q = new LinkedList<>();
        q.offer(root);

        while (!q.isEmpty()) {
            int size = q.size();
            depth++;

            for (int i = 0; i < size; i++) {
                root = q.poll();
                for (Node cur : root.children) {
                    q.offer(cur);
                }
            }
        }

        return depth;
    }
}