前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【每日一题】847. 访问所有节点的最短路径:BFS & 状态压缩 & 小白也能看懂的题解!

【每日一题】847. 访问所有节点的最短路径:BFS & 状态压缩 & 小白也能看懂的题解!

作者头像
彤哥
发布2021-08-12 11:47:19
7150
发布2021-08-12 11:47:19
举报
文章被收录于专栏:彤哥读源码彤哥读源码

题目描述

存在一个由 n 个节点组成的无向连通图,图中的节点按从 0 到 n - 1 编号。

给你一个数组 graph 表示这个图。其中,graph[i] 是一个列表,由所有与节点 i 直接相连的节点组成。

返回能够访问所有节点的最短路径的长度。你可以在任一节点开始和停止,也可以多次重访节点,并且可以重用边。

示例 1:

输入:graph = [[1,2,3],[0],[0],[0]] 输出:4 解释:一种可能的路径为 [1,0,2,0,3]

示例 2:

输入:graph = [[1],[0,2,4],[1,3,4],[2],[1,2]] 输出:4 解释:一种可能的路径为 [0,1,4,2,3]

提示:

代码语言:javascript
复制
n == graph.length
1 <= n <= 12
0 <= graph[i].length < n
graph[i] 不包含 i
如果 graph[a] 包含 b ,那么 graph[b] 也包含 a
输入的图总是连通图

链接:https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes

分析题目

首先,题目要求最短路径,所以,我们可以考虑使用BFS来做,但是,这里有个问题。

在传统的BFS中,我们需要一个visited记录被访问过的节点,防止BFS回头访问。

但是,本题我们不能这么做,请看下图,考虑 0 这个节点,从 1->0 访问一次,从 1->0->2->0 访问第二次,这是合法的,而且我们也必须这么来做。

所以,我们需要记录整个走过的路径做为visited的key来记录某个节点在这条路径下是否访问过。

简单点,我们可以直接把路径转换成字符串来作为key,比如,"1->0->2->0"作为0这个节点第二次被访问的key。

但是,如果出现 "1->0->2->0->2->0" 怎么办呢?可以看到进入死循环了,其实这种就算重复访问了,它跟"1->0->2->0"应该看作重复访问。

所以,我们可以考虑使用数组记录 0,1,2 在当前路径下是否访问过,然而,题目已经明确说了 n 不超过 12,所以我们完全可以使用一个 int 类型来存在路径。

比如,我们声明一个 visited[n][1<<n]数组,第一维表示当前节点是否被访问过,第二维表示路径的状态,然后使用位运算来更新这个状态即可。

好了,请看代码,加了详细注释:

代码语言:javascript
复制
class Solution {
    public int shortestPathLength(int[][] graph) {
        int n = graph.length;

        // 多节点同时开始BFS
        boolean[][] visited = new boolean[n][1 << n];
        Queue<int[]> queue = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            // 当前节点,状态
            queue.offer(new int[]{i, 1 << i});
            visited[i][1 << i] = true;
        }

        // 记录BFS的层数,当访问满了所有节点,返回这个层数即可
        int level = 0;
        while (!queue.isEmpty()) {
            level++;
            // 一层一层遍历
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                // 当前节点
                int[] element = queue.poll();
                int curr = element[0];
                int currState = element[1];
                // 下一层的节点
                for (int next : graph[curr]) {
                    // 注意这个位运算,计算路径状态
                    int nextState = currState | (1 << next);
                    // 提前判断访问了下一个节点满足所有节点都访问了,直接返回即可
                    if (nextState == ((1 << n) - 1)) {
                        return level;
                    }
                    // 下一个节点下一个状态未访问过,下探
                    if (!visited[next][nextState]) {
                        queue.offer(new int[]{next, nextState});
                        visited[next][nextState] = true;
                    }
                }
            }
        }

        return 0;
    }
}

时间复杂度计算较复杂,不做要求,运行结果如下:

图片.png

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 彤哥读源码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 分析题目
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档