题目
给你一个整数 n 和一个二维整数数组 queries。
有 n 个城市,编号从 0 到 n - 1。初始时,每个城市 i 都有一条单向道路通往城市 i + 1( 0 <= i < n - 1)。
queries[i] = [ui, vi] 表示新建一条从城市 ui 到城市 vi 的单向道路。每次查询后,你需要找到从城市 0 到城市 n - 1 的最短路径的长度。
返回一个数组 answer,对于范围 [0, queries.length - 1] 中的每个 i,answer[i] 是处理完前 i + 1 个查询后,从城市 0 到城市 n - 1 的最短路径的长度。
方法一:广度优先搜索
因为城市之间的道路的长度都是 1,即边权相同,所以我们可以使用广度优先搜索算法来获取两个城市之间的最短路径。具体地,我们首先构造一个图 neighbors,neighbors[i] 表示城市 i 可以通往的其他城市集合。那么初始时,对于 0≤i<n−1,有 neighbors[i]={i+1},表示从城市 i 有一条单向道路通往城市 i+1。然后我们遍历查询数组 queries,令当前遍历的查询值为 [u,v],我们将 v 加入到 neighbors[u] 中,然后对新的图 neighbors 执行广度优先搜索算法,获取城市 0 到城市 n−1 的最短路径长度。遍历结束后,返回最终结果。
class Solution {
public:
vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>>& queries) {
vector<vector<int>> prev(n);
vector<int> dp(n);
vector<int> ans;
for(int i=1;i<n;i++){
prev[i].push_back(i-1);
dp[i]=i;
}
for(auto querry : queries){
prev[querry[1]].push_back(querry[0]);
for(int i=querry[1];i<n;i++){
for(int t : prev[i]){
dp[i] = min(dp[i],dp[t]+1);
}
}
ans.push_back(dp[n-1]);
}
return ans;
}
};
方法二:动态规划
根据题意,对于任一单向道路的起始点 u,终止点 v,都有 u<v,那么从城市 0 到任一城市的路径上,所经过的城市编号是单调递增的。令 dp[i] 表示城市 0 到城市 i 的最短路径,同时使用 prev[i] 记录通往城市 i 的所有单向道路的起始城市集合,那么对于 i>0,有 dp[i]=min j∈prev[i]dp[j]+1。根据以上推论,我们可以遍历 queries,在每次查询时,更新 prev 数组,然后更新 dp 数组。注意到,每次新建一条从城市 u 到城市 v 的单向道路时,只有 i≥v 的 dp[i] 会发生变化,因此更新 dp 可以从 v 开始更新。
class Solution {
public:
vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>> &queries) {
vector<vector<int>> prev(n);
vector<int> dp(n);
for (int i = 1; i < n; i++) {
prev[i].push_back(i - 1);
dp[i] = i;
}
vector<int> res;
for (auto &query : queries) {
prev[query[1]].push_back(query[0]);
for (int v = query[1]; v < n; v++) {
for (int u : prev[v]) {
dp[v] = min(dp[v], dp[u] + 1);
}
}
res.push_back(dp[n - 1]);
}
return res;
}
};