Leetcode3243. 新增道路查询后的最短距离 I

Every day a Leetcode

题目来源:3243. 新增道路查询后的最短距离 I

解法1:广度优先搜索

暴力。

每次加边后重新跑一遍 BFS,求出从 0 到 n−1 的最短路。

代码:

/*
 * @lc app=leetcode.cn id=3243 lang=cpp
 *
 * [3243] 新增道路查询后的最短距离 I
 */

// @lc code=start

// 广度优先搜索

class Solution
{
public:
    vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>> &queries)
    {
        vector<int> e[n];
        // 建图
        for (int i = 1; i < n; i++)
            e[i - 1].push_back(i);

        auto bfs = [&]()
        {
            int dis[n];
            memset(dis, -1, sizeof(dis));
            queue<int> q;
            q.push(0);
            dis[0] = 0;
            while (!q.empty())
            {
                int sn = q.front();
                q.pop();
                for (int fn : e[sn])
                    if (dis[fn] == -1)
                    {
                        q.push(fn);
                        dis[fn] = dis[sn] + 1;
                    }
            }
            return dis[n - 1];
        };

        vector<int> ans;
        for (vector<int> &q : queries)
        {
            e[q[0]].push_back(q[1]);
            int res = bfs();
            ans.push_back(res);
        }
        return ans;
    }
};
// @lc code=end

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(q(n+q)),其中 q 是数组 queries 的长度。每次 BFS 的时间是 O(n+q)。

空间复杂度:O(n+q),其中 q 是数组 queries 的长度。

解法2:动态规划

定义 dp[i] 为从 0 到 i 的最短路。

用 from[i] 记录额外添加的边的终点是 i,起点列表是 from[i]。

我们可以从 i−1 到 i,也可以从 from[i][j] 到 i,这些位置作为转移来源,用其 dp 值 +1 更新 dp[i] 的最小值。

初始值:dp[i]=i。

答案:dp[n−1]。

注意:设添加的边为 l→r,只有当 dp[l]+1<dp[r] 时才更新 DP。

代码:

/*
 * @lc app=leetcode.cn id=3243 lang=cpp
 *
 * [3243] 新增道路查询后的最短距离 I
 */

// @lc code=start

// 动态规划

class Solution
{
public:
    vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>> &queries)
    {
        vector<int> dp(n);
        vector<vector<int>> from(n);
        // 初始化:dp[i] = i
        iota(dp.begin(), dp.end(), 0);

        vector<int> ans;
        // 状态转移
        for (vector<int> &q : queries)
        {
            int l = q[0], r = q[1];
            from[r].push_back(l);
            if (dp[l] + 1 < dp[r])
            {
                dp[r] = dp[l] + 1;
                // 更新后面的最短路
                for (int i = r + 1; i < n; i++)
                {
                    dp[i] = min(dp[i], dp[i - 1] + 1);
                    for (int j : from[i])
                    {
                        // 存在一条 j->i 的路径
                        dp[i] = min(dp[i], dp[j] + 1);
                    }
                }
            }
            ans.push_back(dp[n-1]);
        }
        return ans;
    }
};
// @lc code=end

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(q(n+q)),其中 q 是数组 queries 的长度。

空间复杂度:O(n+q),其中 q 是数组 queries 的长度。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值