BFS&DFS&DP

  • 题目描述
  • DFS
  • BFS
  • DP

题目描述

小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下:

1.有 n 名玩家,所有玩家编号分别为 0 ~ n-1,其中小朋友 A 的编号为 0
2.每个玩家都有固定的若干个可传信息的其他玩家(也可能没有)。传信息的关系是单向的(比如 A 可以向 B 传信息,但 B 不能向 A 传信息)。
3.每轮信息必须需要传递给另一个人,且信息可重复经过同一个人

给定总玩家数 n,以及按 [玩家编号,对应可传递玩家编号] 关系组成的二维数组 relation。返回信息从小 A (编号 0 ) 经过 k 轮传递到编号为 n-1 的小伙伴处的方案数;若不能到达,返回 0。

链接:https://leetcode-cn.com/problems/chuan-di-xin-xi

示例 1:

输入:n = 5, relation = [[0,2],[2,1],[3,4],[2,3],[1,4],[2,0],[0,4]], k = 3

输出:3

解释:信息从小 A 编号 0 处开始,经 3 轮传递,到达编号 4。共有 3 种方案,分别是 0->2->0->4, 0->2->1->4, 0->2->3->4。

DFS

可以把传信息的关系看成有向图,每个玩家对应一个节点,每个传信息的关系对应一条有向边。

如 x 可以向 y 传信息,则对应从节点 x 到节点 y 的一条有向边。

寻找从编号 0 的玩家经过 k 轮传递到编号 n−1 的玩家处的方案数,等价于在有向图中寻找从节点 0 到节点 n−1 的长度为 k 的路径数,同一条路径可以重复经过同一个节点。

可以使用深度优先搜索计算方案数。从节点 0 出发做深度优先搜索,每一步记录当前所在的节点以及经过的轮数,当经过 k 轮时,如果位于节点 n−1,则将方案数加 1。搜索结束之后,即可得到总的方案数。

具体实现方面,可以对传信息的关系进行预处理,使用列表存储有向边的关系,即可在 O(1) 的时间内得到特定节点的相邻节点(即可以沿着有向边一步到达的节点)。

class Solution {// 定义全局变量List<List<Integer>> edges;  // 存储有向边的关系int n, k, way;public int numWays(int n, int[][] relation, int k) {this.n = n;this.k = k;edges = new ArrayList<List<Integer>>();// 初始化边for(int i = 0; i < n; i++) {edges.add(new ArrayList<Integer>());}// 添加边for (int[] edge: relation) {int src = edge[0];int dst = edge[1];edges.get(src).add(dst);}dfs(0, 0);return way;}public void dfs(int src, int steps) {if (steps == k) {if (src == n-1)way++;return;}for (int nextIndex: edges.get(src)) {dfs(nextIndex, steps+1);}}
}

复杂度分析

  • 时间复杂度:O(n^k)。最多需要遍历 k 层,每层遍历最多有 O(n) 个分支。
  • 空间复杂度: O(n+m+k)。其中m为relation数组长度。空间复杂度主要取决于图的大小和递归调用栈的深度,保存有向图信息所需空间为O(n+m),递归调用栈的深度不会超过 k。

BFS

也可以使用广度优先搜索计算方案数。从节点 0 出发做广度优先搜索,当遍历到 k 层时,如果位于节点 n−1,则将方案数加 1。搜索结束之后,即可得到总的方案数。

class Solution {public int numWays(int n, int[][] relation, int k) {List<List<Integer>> edges = new ArrayList<List<Integer>>();for (int i = 0; i < n; i++) {edges.add(new ArrayList<Integer>());}for (int[] edge : relation) {int src = edge[0], dst = edge[1];edges.get(src).add(dst);}int steps = 0;Queue<Integer> queue = new LinkedList<Integer>();queue.offer(0);while (!queue.isEmpty() && steps < k) {steps++;int size = queue.size();for (int i = 0; i < size; i++) {int index = queue.poll();List<Integer> list = edges.get(index);for (int nextIndex : list) {queue.offer(nextIndex);}}}int ways = 0;// 判断是否步数为kif (steps == k) {while (!queue.isEmpty()) {if (queue.poll() == n - 1) {ways++;}}}return ways;}
}

复杂度分析

  • 时间复杂度:O(n^k)。最多需要遍历 k 层,每层遍历最多有 O(n) 个分支。
  • 空间复杂度:O(n+m+n^k)。其中m为relation数组的长度。空间复杂度主要取决于图的大小和队列的大小,保存有向图信息所需空间为O(n+m),由于每层遍历最多有O(n)个分支,因此遍历k层时,队列大小O(n ^ k)。

DP

前两种方法都是通过在图中搜索计算方案数。可以换一个思路,这道题是计数问题,可以使用动态规划的方法解决。

定义动态规划的状态 dp[i][j]为经过i轮传递到编号j的玩家的方案数。

由于编号从0开始,当i=0时,一定位于编号0的玩家,不会传递到其他玩家,因此动态规划边界情况下:


对于传信息的关系 [src, dist],如果第i轮传递编号src的玩家,则第i+1轮可以从 src 传递到 dst 的玩家。因此在计算 dp[i+1][dst],需要考虑可以传递到编号dst的所有玩家。


最终得到 dp[k][n−1] 即为总的方案数。

class Solution {public int numWays(int n, int[][] relation, int k) {int[][] dp = new int[k + 1][n];dp[0][0] = 1;for (int i = 0; i < k; i++) {for (int[] edge : relation) {int src = edge[0], dst = edge[1];dp[i + 1][dst] += dp[i][src];}}return dp[k][n - 1];}
}

dp[i][]的值只与dp[i-1][]有关,因此可以把二维数组变为一维数组.

class Solution {public int numWays(int n, int[][] relation, int k) {int[] dp = new int[n];dp[0] = 1;for (int i = 0; i < k; i++) {int[] next = new int[n];for (int[] edge : relation) {int src = edge[0], dst = edge[1];next[dst] += dp[src];}dp = next;}return dp[n - 1];}
}

复杂度分析

  • 时间复杂度:O(km)。其中 m 为relation 数组的长度。
  • 空间复杂度:O(n)。

BUG代码:

class Solution {public int numWays(int n, int[][] relation, int k) {int[][] dp = new int[2][n];dp[0][0] = 1;for (int i = 0; i < k; i++) {for (int[] edge: relation) {int src = edge[0];int dst = edge[1];dp[((i+1)&1)][dst] += dp[(i&1)][src];                }}return dp[1][n-1];}
}

leetcode LCP 07. 传递信息相关推荐

  1. LeetCode LCP 07. 传递信息 / NC111 最大数 / NC16 判断二叉树是否对称 / NC13 二叉树的最大深度

    祝我党百年华诞生日快乐 LCP 07. 传递信息 2021.7.1 每日一题 题目描述 小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下:有 n 名玩家,所有玩家编号分别为 0 - n-1 ...

  2. leetcode LCP 07.传递信息

    原题 LCP 07.传递信息 题解 方法一 动态规划 动态规划说明某一种状态一定与前一种或者前几种状态有关.我们不妨设立一个二维数组ans,其中ans[j][i]表示的是,从0开始,通过j+1步到达i ...

  3. 【力扣-LeetCode】LCP 07. 传递信息 C++题解

    LCP 07. 传递信息 难度简单248收藏分享切换为英文接收动态反馈 小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下: 有 n 名玩家,所有玩家编号分别为 0 - n-1,其中小朋友 ...

  4. 文巾解题 LCP 07. 传递信息

    1 题目描述 2 解题思路 2.1 动态规划 定义动态规划的状态 dp[i][j] 为经过 i 轮传递到编号 j 的玩家的方案数,其中0≤i≤k,0≤j<n. 由于从编号 0 的玩家开始传递,当 ...

  5. LCP 07. 传递信息

    小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下: 有 n 名玩家,所有玩家编号分别为 0 - n-1,其中小朋友 A 的编号为 0 每个玩家都有固定的若干个可传信息的其他玩家(也可能没有 ...

  6. LCP 07. 传递信息 (Python 实现)

    题目: 小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下: 1.有 n 名玩家,所有玩家编号分别为 0 - n-1,其中小朋友 A 的编号为 0 2.每个玩家都有固定的若干个可传信息的其他 ...

  7. ⭐算法入门⭐《二分枚举》简单15 —— LeetCode LCP 18. 早餐组合

    文章目录 一.题目 1.题目描述 2.基础框架 3.原题链接 二.解题报告 1.思路分析 2.时间复杂度 3.代码详解 三.本题小知识 四.加群须知 一.题目 1.题目描述   小扣在秋日市集选择了一 ...

  8. LeetCode——LCP 29. 乐团站位[简单]——分析及代码(Java)

    LeetCode--LCP 29. 乐团站位[简单]--分析及代码[Java] 一.题目 二.分析及代码 1. 直接计算 (1)思路 (2)代码 (3)结果 三.其他 一.题目 某乐团的演出场地可视作 ...

  9. leetcode - LCP 42. 玩具套圈 -二分 -坐标映射 -区间查找 - 坐标范围快速查找

    文章目录 解法1 - 给定圈,找套中的玩具 - 超时 解法 2 - 给定玩具找能套中它的圈 - 超时 解法 3 解法2的基础上加入 二分查找区间 - 通过 解法4 - 解法2的基础上 映射x的同时映射 ...

最新文章

  1. 原生js实现ajax的文件异步提交功能、图片预览功能.实例
  2. ieee文章作者对不齐怎么办呢?
  3. html弹出文本输入框,Windows API 弹出文本框输入的内容
  4. .net core 上传文件大小限制 webconfig
  5. Python面向对象基础一
  6. HDU1572 下沙小面的(2)【全排列】
  7. 三年磨一剑!CEL再度推出专业级FDM 3D打印机
  8. Spring的三大核心思想
  9. linux数学软件,使用这些Linux应用来征服你的数学学习
  10. 互联网晚报 | 1月17日 星期一 | 飞猪推出买机票送核酸检测券服务;洋码头首个文旅场景免税店开业;2022年春运今日开启...
  11. 使用短信接口进行通知
  12. icon图标制作与使用
  13. Adobe Illustrator CS6 出现错误报告16
  14. Database—DML
  15. 软件测试如何快速入门
  16. 集体封盘,深度回撤,量化私募的高光时刻已不再?
  17. 【经验分享】Web前端开发测试常见问题总结
  18. 001-课程体系以及环境搭建
  19. Python 学习归纳
  20. 计算机二级证书北京联合大学,北京联合大学是几本

热门文章

  1. iPhone软件开发之iDP使用,以及真机调试
  2. java语言基于什么区别_Java语言程序有几种?它们有什么区别?
  3. 有这么一种茶几,它带着触摸屏!
  4. Vue 移动端、PC 端适配
  5. Echarts 实现炫酷仪表盘
  6. mfc 操作word2007
  7. FACE++学习二、获得face属性
  8. Download模块 (十二)
  9. 通过大量地铁拍卡数据分析地铁发车时间间隔
  10. 云呐|固定资产标签化管理,固定资产规范化管理