2024.3.5力扣每日一题——到达目的地的方案数

news/2024/7/20 21:06:11 标签: leetcode, 深度优先, 算法, java, 数据结构

2024.3.5

      • 题目来源
      • 我的题解

题目来源

力扣每日一题;题序:1976

我的题解

方法一 深度优先遍历(超时)

从节点0开始进行深度优先遍历,直到遍历到节点n-1结束,遍历过程记录路径和。

时间复杂度:O(E+m)。E表示边数,m表示节点数
空间复杂度:O(m+E)

java">TreeMap<Long,Long> map=new TreeMap<>();
public int countPaths(int n, int[][] roads) {
    List<Integer>[] g=createGraph(n,roads);
    boolean[] visited=new boolean[n];
    visited[0]=true;
    dfs(g,0,-1,0,visited,n);
    return (int)(map.firstEntry().getValue()%1000000007);

}
//构建图
public List<Integer>[] createGraph(int n,int[][] edges){
    List<Integer>[] g=new ArrayList[n];
    for(int i=0;i<n;i++){
        g[i]=new ArrayList<>();
    }
    for(int[] t:edges){
        int from = t[0];
        int to = t[1];
        int weight = t[2];
        g[from].add(to);
        g[from].add(weight);
        g[to].add(from);
        g[to].add(weight);
    }
    return g;
}
//深度优先遍历
public void dfs(List<Integer>[] g,int cur,int pre,long count,boolean[] visited,int n){
    if(cur==n-1)
        map.put(count,map.getOrDefault(count,0L)+1);
    for(int i=0;i<g[cur].size();i+=2){
        int next=g[cur].get(i);
        int weight=g[cur].get(i+1);
        if(!visited[next]){
            visited[next]=true;
            dfs(g,next,cur,count+weight,visited,n);
            visited[next]=false;
        }
    }
}
方法二 最短路径算法(Dijkstra 算法)+优先队列

具体的实现可以看官方题解,我有点没看明白
传统的Dijkstra 算法可以求得两个节点之间的最短路径,但是本题要求求出和最短路径长度相同的路径数。因此,需要对Dijkstra算法进行一些优化。
观察优先队列实现的「Dijkstra 算法」,有以下数据结构

  • e是邻接表,这道题中需要我们自己根据 roads 创建。
  • q 是优先队列,元素是路径长度和点的编号。不停往外抛出队列中的最短路径和点。如果这个点是未被确定最短路径的点,那么这次出队列的操作,就将确定源到这个点的最短路径。然后依次访问这个点相邻的点,判断从这个点到相邻的点的路径,是否能刷新源相邻点的最短路径,如果能,则将路径长度和相邻点放入队列。
  • dis 用来记录源到各个点当前最短路径的长度。会在访问当前出队列点的相邻点的过程中被刷新。
  • vis用来记录哪些点的最短路径已经被确定。在这里略显多余,可以用当前出队列的路径长度和点的最短路径的比较来代替。

除此之外,还需要一个新的数组 ways。ways[v] 就表示源到点 v最短的路径数目,且最短路径长度为 dis[v]。 ways的更新时机与 dis 相同。在访问当前点 u 的各个相邻点 v 时,

  • 如果从点 u 到点 v 路径,能刷新 dis[v],则更新 dis[v],并将 ways[v] 更新为 ways[u],表示有多少条源到点 u 的最短路径,就有多少条源到点 v的最短路径。
  • 如果从点 u 到点 v 路径,与 dis[v]相等。那么 ways[v] 的值要加上 ways[u],表示点 u 到点 v 路径贡献了另一部分源到点 v 的最短路径。
  • 如果从点 u 到点 v 路径,大于 dis[v]。那么无需操作 dis[v]。

时间复杂度:O(mlogm)
空间复杂度:O(m)

java">public int countPaths(int n, int[][] roads) {
    int mod = 1000000007;
    List<int[]>[] e = new List[n];
    for (int i = 0; i < n; i++) {
        e[i] = new ArrayList<int[]>();
    }
    //构建图
    for (int[] road : roads) {
        int x = road[0], y = road[1], t = road[2];
        e[x].add(new int[]{y, t});
        e[y].add(new int[]{x, t});
    }
    // 节点0到每个节点的距离
    long[] dis = new long[n];
    Arrays.fill(dis, Long.MAX_VALUE);
    //表示源到其他节点的最短的路径数目,且最短路径长度为 dis
    int[] ways = new int[n];
	//使用
    PriorityQueue<long[]> pq = new PriorityQueue<long[]>((a, b) -> Long.compare(a[0], b[0]));
    pq.offer(new long[]{0, 0});
    //到本身的距离为0
    dis[0] = 0;
    //只有一个节点
    ways[0] = 1;

    while (!pq.isEmpty()) {
        long[] arr = pq.poll();
        long t = arr[0];
        int u = (int) arr[1];
       	//如果当前堆顶的距离大于现有节点位置,不用更新
        if (t > dis[u]) {
            continue;
        }
        //
        for (int[] next : e[u]) {
            int v = next[0], w = next[1];
            if (t + w < dis[v]) {
                dis[v] = t + w;
                ways[v] = ways[u];
                pq.offer(new long[]{t + w, v});
            } else if (t + w == dis[v]) {
                ways[v] = (ways[u] + ways[v]) % mod;
            }
        }
    }
    return ways[n - 1];
}

有任何问题,欢迎评论区交流,欢迎评论区提供其它解题思路(代码),也可以点个赞支持一下作者哈😄~


http://www.niftyadmin.cn/n/5468377.html

相关文章

语言模型进化史(上)

由于篇幅原因&#xff0c;本文分为上下两篇&#xff0c;上篇主要讲解语言模型从朴素语言模型到基于神经网络的语言模型&#xff0c;下篇主要讲解现代大语言模型以及基于指令微调的LLM。文章来源是&#xff1a;https://www.numind.ai/blog/what-are-large-language-models 一、语…

leetcode 热题 100(部分)C/C++

leetcode 热题 100 双指针 盛最多水的容器 【mid】【双指针】 思路&#xff1a; 好久没写代码sb了&#xff0c;加上之前写的双指针并不多&#xff0c;以及有点思维定势了。我对双指针比较刻板的印象一直是两层for循环i&#xff0c;j&#xff0c;初始时i,j都位于左界附近&…

Juniper MX搭建LDP信令的VPLS组网

简介 本实验使用Juniper vMX 在PNET-LAB上运行搭建&#xff0c;使用LDP信令搭建VPLS。 Juniper 系列文章&#xff1a;https://songxwn.com/categories/Juniper/ 基础理论 VPLS称为虚拟专用局域网业务&#xff08;Virtual Private LAN Service&#xff09;&#xff0c;是公用…

Oracle数据库安全管理与数据加密技术

一、引言 数据安全性的重要性 在现代社会中&#xff0c;信息安全已经成为国家安全和企业安全的重要组成部分。随着人们对数字数据的使用越来越频繁&#xff0c;保护数字信息的安全性和完整性变得越来越重要。对于企业和个人用户来说&#xff0c;数据安全比任何时候都要重要&a…

分布式IO模块PLC扩展模拟量模块

BL200是一款结构紧凑、体积小的分布式IO耦合器,支持ModbusTCP协议,采用嵌入式硬件,主频380Mhz,基于LinuxOS,采用独特的MAC层数据交换技术的双网口技术实现级联,中间设备宕机不影响后面设备的数据传输,可支持高达32个AI、DI、DO、热电阻、热电偶、RS485等种类的IO板,广泛应用于工…

Educational Codeforces Round 133 (Rated for Div. 2) C. Robot in a Hallway

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e18, maxm 4e4 5; c…

构建企业级微服务平台:实现可扩展性、弹性和高效性

在软件开发的快速发展领域中&#xff0c;企业不断努力构建健壮、可扩展和高效的系统。随着微服务架构的出现&#xff0c;再加上云原生技术的应用&#xff0c;创建敏捷且具有弹性的平台的可能性是无限的。在本指南中&#xff0c;我们将深入探讨使用强大的工具和技术组合&#xf…

算法训练营第29天|LeetCode 491.递增子序列 46.全排列 47.全排列Ⅱ

LeetCode 491.递增子序列 题目链接&#xff1a; LeetCode 491.递增子序列 解题思路&#xff1a; 用哈希集合进行去重&#xff0c;同一树层不能取重复元素。 代码&#xff1a; class Solution { public:vector<vector<int>>result;vector<int>path;void…