Every day a Leetcode
题目来源:1466. 重新规划路线
解法1:深度优先搜索
n 座城市,从 0 到 n-1 编号,其间共有 n-1 条路线。
因此,要想在两座不同城市之间旅行只有唯一一条路线可供选择(路线网形成一颗树)。
如果忽略边的方向,将每条有向边以及其反向边加入到图中,那么从任意一点出发都能到达 0 号点。路径上可能会经过反向边,我们需要变更与之对应的原边的方向。需要变更的次数即为答案。
以每个点为起点进行搜索的代价会很大,因此我们考虑从 0 出发去遍历其他点,原来我们需要统计反向边的数量,现在需要统计原方向边的数量。
具体而言,我们使用 1 标记原方向的边,使用 0 标记反向边。然后从 0 号点开始遍历,访问到某个新的点时,所经过的边被 1 标记,就令答案加 1。最终统计得到的答案就是我们需要变更方向的最小路线数。
代码:
/*
* @lc app=leetcode.cn id=1466 lang=cpp
*
* [1466] 重新规划路线
*/
// @lc code=start
// 深度优先搜索
class Solution
{
public:
int minReorder(int n, vector<vector<int>> &connections)
{
vector<vector<pair<int, int>>> edges(n);
for (vector<int> connection : connections)
{
int from = connection[0], to = connection[1];
// 1 表示原树中有一条 a->b 的边
edges[from].push_back(pair<int, int>(to, 1));
// 0 表示反向边
edges[to].push_back(pair<int, int>(from, 0));
}
function<int(int, int)> dfs = [&](int x, int father) -> int
{
int res = 0;
for (pair<int, int> edge : edges[x])
if (edge.first != father)
{
// 原树中有一条 x->edge.first 的边,需要反向
if (edge.second == 1)
res++;
// 递归求解
res += dfs(edge.first, x);
}
return res;
};
return dfs(0, -1);
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(n),其中 n 是树中节点的数量。
空间复杂度:O(n),其中 n 是树中节点的数量。建树的空间复杂度为 O(n),递归所需要的栈空间为 O(n),因此总的空间复杂度为 O(n)。
解法2:广度优先搜索
代码:
class Solution
{
public:
int minReorder(int n, vector<vector<int>> &connections)
{
vector<vector<pair<int, int>>> edges(n);
for (vector<int> connection : connections)
{
int from = connection[0], to = connection[1];
// 1 表示原树中有一条 a->b 的边
edges[from].push_back(pair<int, int>(to, 1));
// 0 表示反向边
edges[to].push_back(pair<int, int>(from, 0));
}
queue<int> q;
vector<bool> visited(n, false);
q.push(0);
visited[0] = true;
int res = 0;
while (!q.empty())
{
int x = q.front();
q.pop();
for (pair<int, int> edge : edges[x])
{
int y = edge.first;
if (visited[y] == false)
{
visited[y] = true;
q.push(y);
if (edge.second == 1)
res++;
}
}
}
return res;
}
};
结果:
复杂度分析:
时间复杂度:O(n),其中 n 是树中节点的数量。
空间复杂度:O(n),其中 n 是树中节点的数量。建树的空间复杂度为 O(n)。