Medium
题目描述
有 n 种单位,编号从 0 到 n - 1。给你一个长度为 n - 1 的二维整数数组 conversions,其中 conversions[i] = [sourceUniti, targetUniti, conversionFactori]。这表示一个 sourceUniti 类型的单位等价于 conversionFactori 个 targetUniti 类型的单位。
返回一个长度为 n 的数组 baseUnitConversion,其中 baseUnitConversion[i] 是与一个类型 0 的单位等价的类型 i 的单位数量。由于答案可能很大,返回每个 baseUnitConversion[i] 模 10^9 + 7 的结果。
示例 1:
输入:conversions = [[0,1,2],[1,2,3]]
输出:[1,2,6]
解释:
- 使用 conversions[0] 将一个类型 0 的单位转换为 2 个类型 1 的单位。
- 使用 conversions[0] 然后 conversions[1] 将一个类型 0 的单位转换为 6 个类型 2 的单位。
示例 2:
输入:conversions = [[0,1,2],[0,2,3],[1,3,4],[1,4,5],[2,5,2],[4,6,3],[5,7,4]]
输出:[1,2,3,8,10,6,30,24]
约束条件:
- 2 <= n <= 10^5
- conversions.length == n - 1
- 0 <= sourceUniti, targetUniti < n
- 1 <= conversionFactori <= 10^9
- 保证单位 0 可以通过唯一的转换组合转换为任何其他单位,而不使用反向转换。
解题思路
根据题目描述,这是一个图论问题,可以将单位转换关系建模为一棵有根树,其中根节点是单位 0。
思路分析:
建图阶段:根据 conversions 数组构建邻接表,每条边代表一个转换关系,权重为转换因子。
遍历求解:从根节点 0 开始进行 BFS 或 DFS 遍历,计算从根节点到每个节点的路径权重乘积,这个乘积就是该节点对应单位与单位 0 的转换比例。
处理大数:由于转换因子可能很大,需要在计算过程中取模防止溢出。
具体步骤:
- 构建邻接表存储图的边和权重
- 使用 BFS 从节点 0 开始遍历,初始化结果数组,节点 0 对应值为 1
- 对于每个相邻节点,新的转换值 = 当前节点转换值 × 边的权重
- 所有计算结果都要对 10^9 + 7 取模
推荐使用 BFS 解法,代码简洁且易于理解。
代码实现
class Solution {
public:
vector<int> baseUnitConversions(vector<vector<int>>& conversions) {
int n = conversions.size() + 1;
const int MOD = 1e9 + 7;
vector<vector<pair<int, long long>>> graph(n);
for (auto& conv : conversions) {
graph[conv[0]].push_back({conv[1], conv[2]});
}
vector<long long> result(n, 0);
result[0] = 1;
queue<int> q;
q.push(0);
while (!q.empty()) {
int curr = q.front();
q.pop();
for (auto& [next, factor] : graph[curr]) {
result[next] = (result[curr] * factor) % MOD;
q.push(next);
}
}
vector<int> ans(n);
for (int i = 0; i < n; i++) {
ans[i] = result[i];
}
return ans;
}
};
class Solution:
def baseUnitConversions(self, conversions: List[List[int]]) -> List[int]:
n = len(conversions) + 1
MOD = 10**9 + 7
graph = [[] for _ in range(n)]
for source, target, factor in conversions:
graph[source].append((target, factor))
result = [0] * n
result[0] = 1
queue = [0]
while queue:
curr = queue.pop(0)
for next_unit, factor in graph[curr]:
result[next_unit] = (result[curr] * factor) % MOD
queue.append(next_unit)
return result
public class Solution {
public int[] BaseUnitConversions(int[][] conversions) {
int n = conversions.Length + 1;
const int MOD = 1000000007;
List<(int, long)>[] graph = new List<(int, long)>[n];
for (int i = 0; i < n; i++) {
graph[i] = new List<(int, long)>();
}
foreach (var conv in conversions) {
graph[conv[0]].Add((conv[1], conv[2]));
}
long[] result = new long[n];
result[0] = 1;
Queue<int> queue = new Queue<int>();
queue.Enqueue(0);
while (queue.Count > 0) {
int curr = queue.Dequeue();
foreach (var (next, factor) in graph[curr]) {
result[next] = (result[curr] * factor) % MOD;
queue.Enqueue(next);
}
}
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int)result[i];
}
return ans;
}
}
var baseUnitConversions = function(conversions) {
const n = conversions.length + 1;
const MOD = 1e9 + 7;
const graph = Array(n).fill(null).map(() => []);
for (const [source, target, factor] of conversions) {
graph[source].push([target, factor]);
}
const result = new Array(n).fill(0);
result[0] = 1;
const queue = [0];
while (queue.length > 0) {
const curr = queue.shift();
for (const [next, factor] of graph[curr]) {
result[next] = (result[curr] * factor) % MOD;
queue.push(next);
}
}
return result;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n),其中 n 是单位数量。每个节点和边都只访问一次 |
| 空间复杂度 | O(n),用于存储图的邻接表、结果数组和队列 |