【算法】剑指 Offer II 110. 所有路径|797. 所有可能的路径(多语言实现)

简介: 给定一个有 n 个节点的有向无环图,用二维数组 graph 表示,请找到所有从 0 到 n-1 的路径并输出(不要求按顺序)。graph 的第 i 个数组中的单元都表示有向图中 i 号节点所能到达的下一些结点(译者注:有向图是有方向的,即规定了 a→b 你就不能从 b→a ),若为空,就是没有下一个节点了。

剑指 Offer II 110. 所有路径|797. 所有可能的路径:

给定一个有 n 个节点的有向无环图,用二维数组 graph 表示,请找到所有从 0n-1 的路径并输出(不要求按顺序)。

graph 的第 i 个数组中的单元都表示有向图中 i 号节点所能到达的下一些结点(译者注:有向图是有方向的,即规定了 a→b 你就不能从 b→a ),若为空,就是没有下一个节点了。

样例 1:

在这里插入图片描述

输入:
    graph = [[1,2],[3],[3],[]]
    
输出:
    [[0,1,3],[0,2,3]]
    
解释:
    有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3

样例 2:

在这里插入图片描述

输入:
    graph = [[4,3,1],[3,2,4],[3],[4],[]]
    
输出:
    [[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]

样例 3:

输入:
    graph = [[1],[]]
    
输出:
    [[0,1]]

样例 4:

输入:
    graph = [[1,2,3],[2],[3],[]]
    
输出:
    [[0,1,2,3],[0,2,3],[0,3]]

样例 5:


输入:
    graph = [[1,3],[2],[3],[]]
    
输出:
    [[0,1,2,3],[0,3]]

提示:

  • n == graph.length
  • 2 <= n <= 15
  • 0 <= graph[i][j] < n
  • graph[i][j] != i
  • 保证输入为有向无环图 (GAD)

分析

  • 这道算法题幸好是 无环图 ,要不然就没那么简单了。
  • 遍历路径,找到所有可以到达终点节点的路径就是结果。
  • 大部分语言的题解都是用的动态数据结构,所以可以规避一个问题,那就是你要提前知道结果集的最大数量。
  • C语言由于是手动去申请内存,所以需要知道结果集的最大数量,当然去申请很大的内存肯定就够放,但是本着算法精神,我们应该申请刚好够用的内存。
  • 提示中说 保证输入为有向无环图 (GAD) ,所以我们可以认为节点间一定有着某种排列的顺序,从头到尾怎样可以有最多的路径呢,那就是在保证没有环路的情况下,所有节点都尽可能多的连接着其他节点。
  • 开始节点可以直接到终点节点...途径任何一个节点都能到终点...途径任何二个节点都能到终点..以此类推,所以中间的节点就成了可以任意组合,一共多少种组合,每个节点都是经过或者不经过两种可能,由于头尾的节点是必经经过的,所以最多结果集的数量就是 (n - 2)2 , 也就是 1 << n - 2

题解

java

class Solution {
    public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
        List<List<Integer>> ans   = new ArrayList<>();
        Deque<Integer>      stack = new ArrayDeque<>();
        stack.offerLast(0);
        dfs(graph, stack, ans);
        return ans;
    }

    private void dfs(int[][] graph, Deque<Integer> stack, List<List<Integer>> ans) {
        if (stack.peekLast() == graph.length - 1) {
            ans.add(new ArrayList<>(stack));
            return;
        }
        for (int to : graph[stack.peekLast()]) {
            stack.offerLast(to);
            dfs(graph, stack, ans);
            stack.pollLast();
        }
    }
}

c

void dfs(int **graph, int *graphColSize, int *returnSize, int **returnColumnSizes, int n, int *stack, int stackSize, int **ans) {
    int last = stack[stackSize - 1];
    if (last == n) {
        int *row = malloc(sizeof(int) * stackSize);
        memcpy(row, stack, sizeof(int) * stackSize);
        ans[*returnSize] = row;
        (*returnColumnSizes)[(*returnSize)++] = stackSize;
        return;
    }
    for (int i = 0; i < graphColSize[last]; ++i) {
        int to = graph[last][i];
        stack[stackSize] = to;
        dfs(graph, graphColSize, returnSize, returnColumnSizes, n, stack, stackSize + 1, ans);
    }
}

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int** allPathsSourceTarget(int** graph, int graphSize, int* graphColSize, int* returnSize, int** returnColumnSizes){
    *returnSize = 0;
    *returnColumnSizes = malloc(sizeof(int) * (1 << graphSize - 2));
    int **ans = malloc(sizeof(int *) * (1 << graphSize - 2));
    int *stack = malloc(sizeof(int) * graphSize);
    stack[0] = 0;
    dfs(graph, graphColSize, returnSize, returnColumnSizes, graphSize - 1, stack, 1, ans);
    return ans;
}

c++

class Solution {
private:
    void dfs(vector<vector<int>>& graph, vector<int>& stack, vector<vector<int>>& ans) {
        if (stack.back() == graph.size() - 1) {
            ans.push_back(stack);
            return;
        }
        for (auto& to : graph[stack.back()]) {
            stack.push_back(to);
            dfs(graph, stack, ans);
            stack.pop_back();
        }
    }
public:
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
        vector<vector<int>> ans;
        vector<int> stack;
        stack.push_back(0);
        dfs(graph, stack, ans);
        return ans;
    }
};

python

class Solution:
    def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
        ans = list()
        stack = list()

        def dfs():
            last = stack[len(stack) - 1]
            if last == len(graph) - 1:
                ans.append(stack[:])
                return

            for to in graph[last]:
                stack.append(to)
                dfs()
                stack.pop()

        stack.append(0)
        dfs()
        return ans
        

go

func allPathsSourceTarget(graph [][]int) (ans [][]int) {
    n := len(graph) - 1
    stack := []int{0}
    var dfs func()
    dfs = func() {
        last := stack[len(stack)-1]
        if last == n {
            ans = append(ans, append([]int{}, stack...))
            return
        }
        for _, to := range graph[last] {
            stack = append(stack, to)
            dfs()
            stack = stack[:len(stack)-1]
        }
    }
    dfs()
    return
}

rust

impl Solution {
    pub fn all_paths_source_target(graph: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
        let mut ans: Vec<Vec<i32>> = Vec::new();
        let mut stack: Vec<i32> = Vec::new();
        stack.push(0);
        Solution::dfs(&graph, graph.len() as i32 - 1, &mut stack, &mut ans);
        ans
    }

    fn dfs(graph: &Vec<Vec<i32>>, n: i32, stack: &mut Vec<i32>, ans: &mut Vec<Vec<i32>>) {
        let last = stack[stack.len() - 1];
        if last == n {
            ans.push(stack.clone());
            return;
        }
        graph[last as usize].iter().for_each(|to| {
            stack.push(to.clone());
            Solution::dfs(graph, n, stack, ans);
            stack.pop();
        });
    }
}

原题传送门:https://leetcode-cn.com/problems/bP4bmD/

原题传送门:https://leetcode-cn.com/problems/all-paths-from-source-to-target/


非常感谢你阅读本文~
放弃不难,但坚持一定很酷~
希望我们大家都能每天进步一点点~
本文由 二当家的白帽子:https://developer.aliyun.com/profile/sqd6avc7qgj7y 博客原创~

相关文章
|
5月前
|
算法 Java
算法:Java计算二叉树从根节点到叶子结点的最大路径和
算法:Java计算二叉树从根节点到叶子结点的最大路径和
|
5月前
|
算法
算法修炼-动态规划之路径问题(1)
算法修炼-动态规划之路径问题(1)
|
4月前
|
存储 SQL 算法
LeetCode题目113:多种算法实现 路径总和ll
LeetCode题目113:多种算法实现 路径总和ll
|
2月前
|
算法
基于多路径路由的全局感知网络流量分配优化算法matlab仿真
本文提出一种全局感知网络流量分配优化算法,针对现代网络中多路径路由的需求,旨在均衡分配流量、减轻拥塞并提升吞吐量。算法基于网络模型G(N, M),包含N节点与M连接,并考虑K种不同优先级的流量。通过迭代调整每种流量在各路径上的分配比例,依据带宽利用率um=Σ(xm,k * dk) / cm来优化网络性能,确保高优先级流量的有效传输同时最大化利用网络资源。算法设定收敛条件以避免陷入局部最优解。
|
3月前
|
自然语言处理 Rust 算法
【算法】17. 电话号码的字母组合(多语言实现)
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
【算法】17. 电话号码的字母组合(多语言实现)
|
4月前
|
存储 算法 Unix
掌握Unix路径简化:五种有效算法比较【python力扣71题】
掌握Unix路径简化:五种有效算法比较【python力扣71题】
|
4月前
|
存储 算法 机器人
路径规划的艺术:不同路径 II 的算法深掘【python力扣63题】
路径规划的艺术:不同路径 II 的算法深掘【python力扣63题】
|
4月前
|
存储 算法 数据挖掘
穿越障碍:最小路径和的高效算法比较【python力扣题64】
穿越障碍:最小路径和的高效算法比较【python力扣题64】
|
4月前
|
算法 Java Go
【经典算法】LeetCode 64. 最小路径和(Java/C/Python3/Golang实现含注释说明,Easy)
【经典算法】LeetCode 64. 最小路径和(Java/C/Python3/Golang实现含注释说明,Easy)
27 1
|
4月前
|
算法 自然语言处理 Rust
【算法】16. 最接近的三数之和(多语言实现)
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。