[LeetCode] 2045. 到达目的地的第二短时间

一、摘要

敬告:本人博客将迁移至博客园刘好念的博客!!!以后将逐渐启用CSDN。

本文介绍了一种使用BFS求无向图中第二短的距离的算法,本文算法参考自
Python3 BFS找出第二短路径

通过使用BFS求出题目中给出的路径图(无向联通图)从节点1到节点n的第二短的路径,再根据路径长度计算出需要耗费的时间。
其实本题目的题解栏目下已经有很多优秀的题解了,本文除了是使用C++与其他题解有些许不同外无任何优势。还是建议读者阅读其他高赞题解。

二、题解

由于给给节点上红灯、绿灯的亮暗是一致的,因此将各节点间的边长视作1,只要求出从节点0节点n-1经过的路径长度即可得到总的耗费时间。
因此本题就变成了求节点0节点n-1第二短的长度
需要注意的是,我们要求的是绝对的第二短的路径,如果有两条最短的不同路径长度都为x,那么我还需要继续求得一个大于x的第二短路径。既然是等边长图中,求最短路径我们可以使用BFS。

使用一个队列queue<pair<int, int>>记录所搜到的节点id和从节点0到该节点id的耗时

为了求第二短的距离因此我们是用两个数组vector<int> firstvector<int> second分别记录节点0节点id的第一、二短耗时(初始时都设为最大值,在C++中即为INT_MAX)。
在使用队列进行bfs算法时:

  • 如果下一个可能要入队列的节点n_id需要的耗时n_time小于first[n_id],那么说明节点0节点n_id的最短耗时为n_time,需要入队pair<int,int>(n_id, n_time)``。
  • 如果下一个可能要入队列的节点n_id需要的耗时n_time等于first[n_id],那么说明存在重复的 从节点0节点n_id的耗时相同、但路径不同 的最短耗时,此时不需要入队;
  • 如果下一个可能要入队列的节点n_id需要的耗时n_time大于first[n_id],且小于second[n_id],那么说明节点0节点n_id的第二短耗时为n_time,需要入队pair<int, int>(n_id, n_time)
  • 如果下一个可能要入队列的节点n_id需要的耗时n_time大于等于second[n_id],那么说明存在重复的 从节点0节点n_id的耗时相同、但路径不同 的第二短耗时、或者这是第三短的耗时,此时不需要入队;

代码如下:

class Solution {
public:
    // 图的节点
    struct Node{
        int idx;    // 节点id
        vector<int> neighbor;   // 相邻的节点id
        Node(int i):idx(i){}
    };
    
    // 根据此时的时间now计算经过一条边,到达下一个节点的时间
    int getNextTime(int now, int time, int change){
        if((now/change)%2==0){
            now += time;
        }else{
            now += (change - now%change)+time;
        }
        return now;
    }
    int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
        nodes_.resize(n);
        for(int i=0; i<n; i++){
            nodes_[i] = new Node(i);
        }
        // 建图
        for(int i=0; i<edges.size(); i++){
            int a = edges[i][0] - 1;
            int b = edges[i][1] - 1;
            nodes_[a]->neighbor.push_back(b);
            nodes_[b]->neighbor.push_back(a);
        }

        queue<pair<int, int>> que;
        vector<int> first(n, INT_MAX);  // first记录到达节点i最短的耗时
        vector<int> second(n, INT_MAX); // second记录到达节点i第二短的耗时
        
        que.push(pair<int, int>(0,0));  // 将(0,0)入队,表示达到节点0的耗时为0
        
        while(que.empty()==false){
            int id = que.front().first;
            int now = que.front().second;
            que.pop();
            for(int i=0; i<nodes_[id]->neighbor.size(); i++){
                int n_id = nodes_[id]->neighbor[i];
                int n_time = getNextTime(now, time, change);
                if(n_id==n-1){   // 如果是第n个节点
                    if(first[n_id]==INT_MAX){    // 第一次到达节点n-1,更新first,且pair<int,int>(n_id,n_time)入队
                        first[n_id] = n_time;
                        que.push(pair<int, int>(n_id, n_time));
                    }else if(n_time>first[n_id] && second[n_id]==INT_MAX){  // 到达节点n-1的第二短距离,返回答案
                        second[n_id] = n_time;
                        return n_time;
                    }
                }else{
                    if(first[n_id]==INT_MAX){   // 第一次到达节点n_id,更新first,且pair<int,int>(n_id,n_time)入队
                        first[n_id] = n_time;
                        que.push(pair<int, int>(n_id, n_time));
                    }else if(n_time>first[n_id] && second[n_id]==INT_MAX){  // 到达节点n-1的第二短的距离,更新second,且pair<int,int>(n_id,n_time)入队
                        second[n_id] = n_time;
                        que.push(pair<int, int>(n_id, n_time));
                    }
                }
            }
        }
        return 0;
    }
    vector<Node*> nodes_;
};

复杂度分析:

  • 时间复杂度:O(n+m)
  • 空间复杂度:O(n+m)
    其中n为节点个数,m为边个数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值