方法一:广度优先搜索
前面说到,深度优先搜索是一条路径走到底再回溯。而广度优先搜索是先探索深度相同的所有节点,再拓展深度。如果在树中,就是层序遍历。
此题中,只需从0开始搜索与它直接相连的节点,更新距离。再进一步搜索与这些节点直接相连的节点,继续更新距离即可。
class Solution
{
public:
int bfs(int n, const vector<vector<int>>& graph)
{
vector<int>dis(n, -1);//dis[i]表示节点0到节点i的最短距离
queue<int>que;
que.push(0);
dis[0] = 0;
while (!que.empty())
{
int x = que.front();
que.pop();
for (int t : graph[x])
{
if (dis[t] >= 0)//由于从0开始,所以如果dis[t]已经非负,意味着已经有最短路径了
//举个例子:先连接0与3,再连接0与2。对与2直接相连的节点进行bfs时,会发现dis[3]已经非负了
{
continue;
}
que.push(t);
dis[t] = dis[x] + 1;
}
}
return dis[n - 1];
}
vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>>& queries)
{
vector<vector<int>>graph(n);
for (int i = 0; i < n - 1; i++)
{
graph[i].push_back(i + 1);
}
vector<int>res;
for (auto& q : queries)
{
graph[q[0]].push_back(q[1]);
res.push_back(bfs(n, graph));
}
return res;
}
};
方法二:动态规划
class Solution
{
public:
vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>>& queries)
{
vector<vector<int>>prev(n);//prev[i]中存储的节点都是可以直接到达节点i的
vector<int>dis(n);//节点0到节点i的距离
for (int i = 1; i < n; i++)
{
prev[i].push_back(i - 1);
dis[i] = i;
}
vector<int>ans;
for(auto&q:queries)
{
prev[q[1]].push_back(q[0]);
for(int v=q[1];v<n;v++)
//添加一条q[0]->q[1]的路径后,只有q[1]及其后面的节点到节点0的距离会改变
{
for(int u:prev[v])
{
dis[v]=min(dis[v],dis[u]+1);
}
}
ans.push_back(dis[n-1]);
}
return ans;
}
};
模拟一下就很清晰了。假设是0->1->2->3->4->5.现在我们新建一条路2->4,那么从4开始往后的节点到节点0的最短路长度就会改变。从4开始:这时与4直接相连的节点有3,2.开始遍历这两个节点:当u=3,dis[3]+1=dis[4],不改变;当u=2,dis[2]+1=3<dis[4],更新dis[4]。接着到5:由于改变了dis[4],所以dis[5]也会发生改变。也就是说,这种改变是从前往后推的。