算法练习大厂高频「广度优先搜索」类型题目总结

Posted 在路上的德尔菲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法练习大厂高频「广度优先搜索」类型题目总结相关的知识,希望对你有一定的参考价值。

题目一:二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

示例:
输入:[3,9,20,null,null,15,7],

    3
   / \\
  9  20
    /  \\
   15   7

输出:

[
  [3],
  [9,20],
  [15,7]
]

题解:
层序遍历符合先进先出模型(FIFO),所以适合使用队列。
注意需要2次循环,外循环是判断总体是否还有节点,内循环判断每一层是否还有节点。
另外用size--的方式相比使用startend来控制输出每层节点方便。

    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> list = new ArrayList<>();
            while (size-- > 0) {
                TreeNode node = queue.poll();
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
                list.add(node.val);
            }
            res.add(list);
        }
        return res;
    }
  • 时间复杂度:O(N),N为节点个数,每个节点进队列出队列一次。
  • 空间复杂度:O(N),队列中元素个数不超过N个。

相关题目扩展:
103 二叉树锯齿形层序遍历在这里插入代码片
107二叉树的层序遍历II

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

校招美团二面算法题

题目二:二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]

解释:
   1            <---
 /   \\
2     3         <---
 \\     \\
  5     4       <---

和第一题解题思路类似,都是需要层序遍历,找到每层的最后一个节点。
注意不用2次循环,因为每层只用找到最右一个节点加入返回结果中,不像第一题要把每层所有节点都加入到返回结果中。
题解:

    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        int start = 0, end = 1;
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            start++;
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
            //判断是否为每层的最后一个节点
            //start置0,end 为当前层存在的节点个数
            if (start == end) {
                start = 0;
                end = queue.size();
                res.add(node.val);
            }
        }
        return res;
    }
  • 时间复杂度:O(N),N为节点个数,每个节点进队列出队列一次。
  • 空间复杂度:O(N),队列中元素个数不超过N个。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-right-side-view
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目三:二叉树的最小深度

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

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

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

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

    3
   / \\
  9  20
    /  \\
   15   7

输出:2
首先我们需要自定义一个模型,模型中包括原节点TreeNode和节点的深度。
核心思路为当我们找到一个叶子节点,即左子树和右子树均为null,返回这个叶子节点的深度,结束查找。
如果当前节点存在左子树节点,将左子树节点模型放入队列中,同理如果当前节点存在右子树节点,将右子树节点模型放入队列中,注意子树模型中高度要加1
解题:

    class NodeDep {
        TreeNode node;
        int depth;

        public NodeDep(TreeNode node, int depth) {
            this.node = node;
            this.depth = depth;
        }
    }

    public int minDepth(TreeNode root) {
        if (root == null)return 0;
        Queue<NodeDep> queue = new LinkedList<>();
        queue.offer(new NodeDep(root, 1));
        
        while (!queue.isEmpty()) {
            NodeDep pollNode = queue.poll();
            if (pollNode.node.left == null && pollNode.node.right == null) return pollNode.depth;
            if (pollNode.node.left != null) queue.offer(new NodeDep(pollNode.node.left, pollNode.depth + 1));
            if (pollNode.node.right != null) queue.offer(new NodeDep(pollNode.node.right, pollNode.depth + 1));
        }
        return 0;
    }
  • 时间复杂度:O(N),N为节点个数,每个节点进队列出队列一次。
  • 空间复杂度:O(N),队列中元素个数不超过N个。

此题递归算法见【算法总结】二叉树常见算法题目及解题思路汇总

题目四:01矩阵

给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。

示例:

输入:
[[0,0,0],
 [0,1,0],
 [1,1,1]]

输出:
[[0,0,0],
 [0,1,0],
 [1,2,1]]

记住以下思路:

对于 「Tree 的 BFS」 (典型的「单源 BFS」)
首先把 root 节点入队,再一层一层无脑遍历就行了。
对于 「图 的 BFS」 (「多源 BFS」) 做法其实也是一样滴~,与 「Tree 的 BFS」的区别注意以下两条就 ok 辣~
Tree 只有 1 个 root,而图可以有多个源点,所以首先需要把多个源点都入队;
Tree 是有向的因此不需要标识是否访问过,而对于无向图来说,必须得标志是否访问过哦!并且为了防止某个节点多次入队,需要在其入队之前就将其设置成已访问!避免超时

题解:

  • 1.定义一个队列,里面存放遍历的节点的位置信息 Queue<int[]>
  • 2.先找到所有0的节点放进队列,其他节点标记为-1
  • 3.对队列中每个节点的上下左右节点进行判断,首先是符合边界条件,其次是符合没有被访问过(值为-1)
  • 4.距离为在基础点距离上加1,即mat[xNew][yNew] = mat[x][y] + 1
  • 5.将这个值放入队列中,循环第3步
    public int[][] updateMatrix(int[][] mat) {
        Queue<int[]> queue = new LinkedList<int[]>();
        int n = mat.length, m = mat[0].length;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (mat[i][j] == 0) {
                    queue.offer(new int[]{i, j});
                } else {
                    mat[i][j] = -1;
                }
            }
        }

		//为了构建上下左右四个点方便
        int[] dx = {-1, 1, 0, 0};
        int[] dy = {0, 0, -1, 1};
        while (!queue.isEmpty()) {
            int[] poll = queue.poll();
            int x = poll[0], y = poll[1];
            for (int i = 0; i < 4; i++) {
                int xNew = x + dx[i];
                int yNew = y + dy[i];
                if (xNew >= 0 && xNew < mat.length && yNew >= 0 && yNew < mat[0].length && mat[xNew][yNew] == -1) {
                    mat[xNew][yNew] = mat[x][y] + 1;
                    queue.offer(new int[]{xNew, yNew});
                }
            }
        }
        return mat;
    }
  • 时间复杂度:O(n*m),每个节点进队列出队列一次。
  • 空间复杂度:O(n*m),原地修改原输入数据来存储结果,每个节点都会进入队列。

相关题目扩展:
地图分析1162

以上是关于算法练习大厂高频「广度优先搜索」类型题目总结的主要内容,如果未能解决你的问题,请参考以下文章

广度优先搜索总结

五月集训(第17天) —— 广度优先搜索

广度优先搜索的实际应用

面试题算法: 广度优先搜索

搜索算法

搜索算法