返回
Featured image of post LeetCode LCP 07 - 传递信息

LeetCode LCP 07 - 传递信息

LCP 07. 传递信息

题目:

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

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

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

示例1:

示例 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。

示例2:

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

输出:0

解释:信息不能从小 A 处经过 2 轮传递到编号 2

leetcode链接:LCP 07. 传递信息

题解:

思路1:dfs

题目中的relation很容易抽象成有向图,而对于可行路径的查找也很自然地联想到使用深度优先搜索。主要步骤归纳如下:

  • 有向图初始化
List<List<Integer>> edges;
edges = new ArrayList<>();
for(int i = 0; i < n; i++){
    edges.add(new ArrayList<>());
}
for(int[] edge : relation){
    edges.get(edge[0]).add(edge[1]);
}
  • 深度优先搜索
private void dfs(int cur, int steps){
    if(steps == k){
        if(cur == n - 1){
            res++;
            //System.out.println(res);
        }
        return;
    }
    List<Integer> l = edges.get(cur);
    for(int next : l){
        dfs(next, steps + 1);
    }
}

public int numWays(int n, int[][] relation, int k) {
    ...
    dfs(0,0);
}

合并后即可写出最终代码

class Solution {
    int res, n, k;
    List<List<Integer>> edges;

    public int numWays(int n, int[][] relation, int k) {
        res = 0;
        this.n = n;
        this.k = k;
        edges = new ArrayList<>();
        for(int i = 0; i < n; i++){
            edges.add(new ArrayList<>());
        }
        for(int[] edge : relation){
            edges.get(edge[0]).add(edge[1]);
        }
        dfs(0,0);
        return res;
    }

    private void dfs(int cur, int steps){
        if(steps == k){
            if(cur == n - 1){
                res++;
                //System.out.println(res);
            }
            return;
        }
        
        List<Integer> l = edges.get(cur);
        for(int next : l){
            dfs(next, steps + 1);
        }
    }
}
  • 时间复杂度:O(n^k)。
  • 空间复杂度:O(n+m+k)。

相应的bfs方法也可以解决本题,在此不再赘述

但两者的时间复杂度显而易见地大,翻评论区却发现了一种更巧妙的方法——动态规划。

思路2:动态规划

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 = 1; i < k; i++){
            for(int[] edge : relation){
                dp[i][edge[1]] += dp[i - 1][edge[0]];
            }
        }
        return dp[k][n - 1];
    }
}

动态规划从代码入手更易于理解。dp数组用于存储 第i轮每个小朋友 可达的方案数,其值为可以向 传递信息的小朋友 第i-1轮 可达方案数 的总和。第一层for循环用于遍历轮数,第二层for循环用于遍历边(信息传递的方向)——edge[1]即为该小朋友,edge[0]为可以向他传递信息的小朋友,思路理清后,代码也就呼之欲出了。

comments powered by Disqus