Skip to content

Conversation

@github-actions
Copy link

LeetCode 每日一题:2976. Minimum Cost to Convert String I

题目链接: https://leetcode.com/problems/minimum-cost-to-convert-string-i/
难度: Medium

解题过程

思考过程

我需要先获取题目ID 2976的信息。

思考过程

现在我需要分析题目。这是第2976题:"Minimum Cost to Convert String I"。题目要求计算将源字符串转换为目标字符串的最小成本。我们有一系列的转换规则,每个规则指定了将字符 original[i] 转换为 changed[i] 的成本 cost[i]。我们可以执行任意数量的操作,每次操作可以选择一个字符 x 转换为 y,前提是存在这样的规则。我们需要找到从 source 到 target 的最小总成本,如果不可能则返回 -1。

观察约束条件:source 和 target 的长度最多 10^5,original/changed 数组的长度最多 2000。字符只有 26 个小写字母。因此我们需要为每个字符对 (u, v) 计算最小转换成本,即从字符 u 转换为字符 v 的最小成本,允许通过中间字符转换(类似 Floyd-Warshall 算法)。由于最多只有 26 个节点,我们可以预先计算所有字符对之间的最短路径(最小成本)。然后对于 source 和 target 中每个位置 i,如果 source[i] == target[i],则成本为 0。否则我们需要查找从 source[i] 到 target[i] 的最小成本。如果不可达(即距离为无穷大),则返回 -1。否则累加所有位置的成本。

需要注意的细节:

  • 可能存在多个相同 original->changed 的规则,cost 不同,取最小值。
  • 可以经过多个中间字符转换,因此需要使用 Floyd-Warshall 计算所有对最短路径。
  • 由于字符只有 26 个,Floyd-Warshall 的时间复杂度 O(26^3) 可以忽略不计。
  • 需要处理大整数:cost 最大为 1e6,长度最多 1e5,总成本可能超过 int 范围,因此使用 long long(函数签名返回 long long,但函数签名中写的是 long?仔细看:函数签名是 long minimumCost(...),但代码模板中是 long long minimumCost(...)。模板中是 long long,应该使用 long long 类型。

算法步骤:

  1. 初始化距离矩阵 dist[26][26],对角线上 dist[c][c] = 0(自身转换成本为 0),其他为 INF。
  2. 遍历给定的规则,对于每个 (original[i], changed[i], cost[i]),更新 dist[original[i]-'a'][changed[i]-'a'] 为 min(现有值, cost[i])。
  3. 运行 Floyd-Warshall 算法:对于每个中间节点 k,遍历所有 i, j,更新 dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])。
  4. 遍历 source 和 target 的每个位置,对于每个位置 i:
    • 如果 source[i] == target[i],跳过(成本为 0)。
    • 否则获取 dist[source[i]-'a'][target[i]-'a'],如果为 INF,返回 -1。
    • 累加成本。
  5. 返回总成本。

时间复杂度:O(26^3 + n + m),其中 n 是 source 长度,m 是规则数量。
空间复杂度:O(26^2) = O(1)。

现在需要生成三个文件:头文件、源文件、测试文件。由于这是一个普通题目(非设计类),应该使用 SolutionBase 模式。根据题目信息,solution_class_name 是 "MinimumCostToConvertStringISolution",solution_class_base 是 "MinimumCostToConvertStringI",test_class_name 是 "MinimumCostToConvertStringITest",namespace 是 "problem_2976"。我需要遵循这些命名。

首先看一下提供的示例 "TwoSum" 的格式。

头文件定义了一个继承自 SolutionBase 的类。Func 是函数类型 std::function<long long(string, string, vector&, vector&, vector&)>?实际上这个问题的函数签名是 long long minimumCost(string source, string target, vector& original, vector& changed, vector& cost)。因此 Func 应该是 std::function<long long(string, string, vector&, vector&, vector&)>。

然后类中定义 public 方法 minimumCost,以及构造函数。构造函数会注册策略。我们可以实现多种策略,但这个问题只有一种明显的算法(Floyd-Warshall),因此我可以只实现一个策略。不过为了展示,我可以实现两种策略:一种是朴素的 Floyd-Warshall,另一种是使用 Dijkstra 算法(每个字符作为源点计算到其他字符的最短路径),但意义不大。还是只实现一个策略即可。

测试文件需要包含多个测试用例,包括题目提供的示例。

现在开始生成代码。

首先,我需要确保在头文件中包含 "leetcode/core.h",并且使用正确的命名空间。

让我编写头文件:

思考过程

现在编译项目验证代码是否正确。

思考过程

很好,编译成功。现在运行测试用例。

思考过程

所有测试通过!很好。

现在我需要输出解题报告,描述思考过程和算法设计。

我会按照要求输出 Markdown 格式的解题报告。

AI 回复

解题报告:LeetCode 2976. Minimum Cost to Convert String I

题目理解

题目要求计算将源字符串 source 转换为目标字符串 target 的最小成本。我们有一系列转换规则,每个规则指定了将字符 original[i] 转换为 changed[i] 的成本 cost[i]。每次操作可以选择一个字符进行转换,前提是存在相应的转换规则。我们可以执行任意多次操作,最终目标是使 source 完全变成 target。如果无法完成转换,返回 -1。

关键点:

  1. 字符串长度最多为 10^5,转换规则数量最多为 2000
  2. 只包含 26 个小写英文字母
  3. 转换规则可能存在重复,应取最小成本
  4. 可以通过中间字符间接转换,形成转换路径

算法设计

这是一个典型的图论最短路径问题。我们可以将 26 个字母看作图中的 26 个节点,每条转换规则 original[i] → changed[i] 看作一条有向边,权重为 cost[i]。问题转化为:

对于每个位置 i:

  1. 如果 source[i] == target[i],成本为 0
  2. 否则,需要计算从 source[i]target[i] 的最短路径长度(最小成本)

由于只有 26 个节点,我们可以预先计算所有字符对之间的最短路径,然后直接查表计算总成本。

算法一:Floyd-Warshall(推荐)

思路

  1. 初始化 26×26 的距离矩阵 dist,对角线为 0(相同字符转换成本为 0),其他为无穷大
  2. 根据给定的转换规则更新直接转换成本,取最小值
  3. 运行 Floyd-Warshall 算法计算所有对最短路径
  4. 遍历字符串的每个位置,累加转换成本

时间复杂度

  • Floyd-Warshall: O(26³) = O(17,576) ≈ O(1)
  • 处理转换规则: O(m),其中 m ≤ 2000
  • 遍历字符串: O(n),其中 n ≤ 10⁵
  • 总复杂度: O(n + m + 26³) ≈ O(n + m)

空间复杂度

  • 距离矩阵: O(26²) = O(1)

算法二:Dijkstra(每个字符作为源点)

思路

  1. 构建邻接表表示字符之间的转换关系
  2. 对每个字符作为源点,运行 Dijkstra 算法计算到其他所有字符的最短距离
  3. 同样遍历字符串累加成本

时间复杂度

  • 26 次 Dijkstra: O(26 × (E log V)),其中 E ≤ 2000,V = 26
  • 遍历字符串: O(n)
  • 总复杂度: O(n + 26 × m log 26) ≈ O(n + m)

空间复杂度

  • 邻接表: O(m)
  • 距离矩阵: O(26²) = O(1)

实现细节

  1. 距离表示:使用 long long 类型存储距离,因为单次成本最大为 10⁶,字符串长度最大为 10⁵,总成本可能达到 10¹¹,超出 32 位整数范围。
  2. 无穷大值:设为 10¹⁸,足够大且不会溢出。
  3. 相同字符处理:直接跳过,不产生成本。
  4. 不可达判断:如果任意位置的转换距离为无穷大,立即返回 -1。

关键点总结

  1. 问题转换:将字符串转换问题转化为图的最短路径问题
  2. 规模分析:只有 26 个字母,可以使用 Floyd-Warshall 等全源最短路径算法
  3. 预处理思想:预先计算所有字符对的最短距离,避免在遍历字符串时重复计算
  4. 边界处理:注意大整数溢出和不可达情况的判断

测试用例设计

测试覆盖了以下场景:

  1. 题目提供的三个示例
  2. 源字符串和目标字符串相同的情况
  3. 直接转换的情况
  4. 间接转换的情况
  5. 同一字符对有多个转换规则的情况(取最小值)
  6. 不可达的情况
  7. 自环规则的情况

所有测试用例均通过,验证了算法的正确性。

✅ 解题完成!代码已通过编译和测试。


本报告由 AI 自动生成,包含完整的思考过程和解题步骤。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants