字符串趋同最小代价问题 | 豆包MarsCode AI 刷题
问题描述
小U 和 小R 各自拥有一个长度相等的二进制字符串 A 和 B。现在,他们想要将这两个字符串修改成相同的字符串。每次修改可以选择以下两种操作:
- 交换同一个字符串中的任意两个字符,交换操作的成本为它们索引之差的绝对值
|i - j|。 - 对某个字符进行取反操作,取反的成本为 2。
小U 和 小R 想知道,将字符串 A 和 B 修改为相同字符串的最小总成本是多少?
测试样例
样例1:
输入:
str1 = "10001",str2 = "10000"输出:2
样例2:
输入:
str1 = "100100",str2 = "100001"输出:2
样例3:
输入:
str1 = "1010",str2 = "0111"输出:3
样例4:
输入:
str1 = "1100",str2 = "0011"输出:4
解题思路
- 输入检查:确保输入字符串长度相等。
- 找出不同字符的位置:遍历字符串,记录不同字符的索引。
- 动态规划初始化:初始化动态规划数组,处理没有不同字符的情况。
- 动态规划更新:通过动态规划计算最小成本,考虑取反和交换操作。
- 返回结果:返回最小总成本。
代码详解
1.输入检查:
首先检查输入的两个字符串 str1 和 str2 的长度是否相等。如果不相等,抛出 ValueError 异常。
if len(str1) != len(str2):
raise ValueError("Input strings must be of equal length")
2.找出不同字符的位置:
遍历两个字符串,找出所有不同字符的索引,并将这些索引存储在列表 diff_id 中。
n = len(str1)
diff_id = []
for i in range(n):
if str1[i] != str2[i]:
diff_id.append(i)
3.动态规划初始化:
- 如果
diff_id为空(即两个字符串完全相同),直接返回0。 - 初始化一个动态规划数组
dp,其中dp[i]表示将前i个不同字符修改为相同字符的最小成本。 dp[1]初始化为2,表示第一个不同字符的取反成本。
m = len(diff_id)
if m == 0:
return 0
# 初始化动态规划数组
dp = [0] * (m + 1)
dp[1] = 2 # 第一个不同字符的取反成本
4.动态规划更新:
-
对于每个不同的字符位置
i,计算取反的成本(dp[i - 1] + 2)。 -
检查是否可以通过交换减少成本:
-
如果
str1[diff_id[i - 2]] != str1[diff_id[i - 1]],则计算交换的成本并更新dp[i]。 -
如果
i >= 4且str1[diff_id[i - 3]] != str1[diff_id[i - 1]]和str1[diff_id[i - 4]] != str1[diff_id[i - 2]],则计算四个字符的交换成本并更新dp[i]。
-
for i in range(2, m + 1):
dp[i] = dp[i - 1] + 2 # 当前不同字符的取反成本
# 检查是否可以通过交换减少成本
if str1[diff_id[i - 2]] != str1[diff_id[i - 1]]:
dp[i] = min(dp[i], dp[i - 2] + abs(diff_id[i - 1] - diff_id[i - 2]))
# 检查是否可以通过交换减少成本(四个字符的情况)
if i >= 4 and str1[diff_id[i - 3]] != str1[diff_id[i - 1]] and str1[diff_id[i - 4]] != str1[diff_id[i - 2]]:
dp[i] = min(dp[i], dp[i - 4] + abs(diff_id[i - 1] - diff_id[i - 3]) + abs(diff_id[i - 2] - diff_id[i - 4]))
知识总结:
-
字符串操作:
- 字符串长度:使用
len(str1)获取字符串的长度。 - 字符串比较:使用
str1[i] != str2[i]比较两个字符串在相同位置的字符是否不同。
- 字符串长度:使用
-
列表操作:
- 列表初始化:使用
diff_id = []初始化一个空列表。 - 列表追加:使用
diff_id.append(i)将元素追加到列表中。 - 列表长度:使用
len(diff_id)获取列表的长度。
- 列表初始化:使用
-
动态规划:
- 动态规划数组初始化:使用
dp = [0] * (m + 1)初始化一个长度为m + 1的动态规划数组。 - 状态转移:使用
dp[i] = dp[i - 1] + 2表示当前不同字符的取反成本。 - 最小成本选择:使用
min(dp[i], dp[i - 2] + abs(diff_id[i - 1] - diff_id[i - 2]))选择最小成本的操作。
- 动态规划数组初始化:使用
-
条件判断:
-
条件语句:使用
if len(str1) != len(str2):检查两个字符串的长度是否相等。 -
多条件判断:使用
if i >= 4 and str1[diff_id[i - 3]] != str1[diff_id[i - 1]] and str1[diff_id[i - 4]] != str1[diff_id[i - 2]]:进行多条件判断。
-
-
异常处理:
- 抛出异常:使用
raise ValueError("Input strings must be of equal length")在输入字符串长度不相等时抛出异常
- 抛出异常:使用
-
测试用例:
- 测试函数:使用
print(solution("10001", "10000") == 2)进行测试,验证代码的正确性。
- 测试函数:使用
学习计划:
1.定期刷题:每天至少一道算法题,思考如何在第一步的基础上,如何优化算法,降低时间复杂度。
2.错题总结:总结一下这道题考察的知识点、切入的角度、同类型的题目等,还要思考有没有更优的办法,代码还能不能更加简洁一些。
工具运用:
豆包MarsCode AI提供了详细的解题思路和代码示例。
向豆包提出问题,可以获得思路启发,便于我们更好的理解和把握如何运用算法去解题。
针对代码中可能出现的语法错误,逻辑漏洞等问题,可以帮忙检查出并给出修改建议,提升代码的准确率和效率
在解完算法题后,可以帮你回顾题目中涉及到的算法知识,数据结构知识等,强化你对这些知识点的掌握程度。并且为你拓展相关的,更深入或者更广泛的算法知识内容,拓展知识面,更好的应对更多类型的算法题。
完整代码实现
def solution(str1, str2):
# 检查输入字符串长度是否相等
if len(str1) != len(str2):
raise ValueError("Input strings must be of equal length")
n = len(str1)
diff_id = []
for i in range(n):
if str1[i] != str2[i]:
diff_id.append(i)
m = len(diff_id)
if m == 0:
return 0
# 初始化动态规划数组
dp = [0] * (m + 1)
dp[1] = 2 # 第一个不同字符的取反成本
for i in range(2, m + 1):
dp[i] = dp[i - 1] + 2 # 当前不同字符的取反成本
# 检查是否可以通过交换减少成本
if str1[diff_id[i - 2]] != str1[diff_id[i - 1]]:
dp[i] = min(dp[i], dp[i - 2] + abs(diff_id[i - 1] - diff_id[i - 2]))
# 检查是否可以通过交换减少成本(四个字符的情况)
if i >= 4 and str1[diff_id[i - 3]] != str1[diff_id[i - 1]] and str1[diff_id[i - 4]] != str1[diff_id[i - 2]]:
dp[i] = min(dp[i], dp[i - 4] + abs(diff_id[i - 1] - diff_id[i - 3]) + abs(diff_id[i - 2] - diff_id[i - 4]))
return dp[m]
if __name__ == "__main__":
# Add your test cases here
print(solution("10001", "10000") == 2)
print(solution("100100", "100001") == 2)
print(solution("1010", "0011") == 3)
print(solution("1100", "0011") == 4)