最大UCC子串计算 | 豆包MarsCode AI刷题
最大UCC子串计算
问题描述
小S有一个由字符 'U' 和 'C' 组成的字符串 ,并希望在编辑距离不超过给定值 的条件下,尽可能多地在字符串中找到 "UCC" 子串。
编辑距离定义为将字符串 转化为其他字符串时所需的最少编辑操作次数。允许的每次编辑操作是插入、删除或替换单个字符。你需要计算在给定的编辑距离限制 下,能够包含最多 "UCC" 子串的字符串可能包含多少个这样的子串。
例如,对于字符串"UCUUCCCCC"和编辑距离限制m = 3,可以通过编辑字符串生成最多包含3个"UCC"子串的序列。
测试样例
样例1:
输入:
m = 3,s = "UCUUCCCCC"
输出:3
样例2:
输入:
m = 6,s = "U"
输出:2
样例3:
输入:
m = 2,s = "UCCUUU"
输出:2
解释
样例1:可以将字符串修改为 "UCCUCCUCC"(2 次替换操作,不超过给定值 m = 3),包含 3 个 "UCC" 子串。
样例2:后面插入 5 个字符 "CCUCC"(5 次插入操作,不超过给定值 m = 6),可以将字符串修改为 "UCCUCC",包含 2 个 "UCC" 子串。
样例3:替换最后 2 个字符,可以将字符串修改为 "UCCUCC",包含 2 个 "UCC" 子串。
解决思路
采用贪心的思想考虑局部最优情况:
编辑距离就是执行操作的次数,你只有插入,替换或删除单个字符这三种操作
对于有限的操作次数,我们可以采用贪心的思想,如何使用最少的步数获得最多的UCC
先检查字符串中是否有0步就能得到的UCC,即现成的UCC进行统计,统计完之后从字符串中排除,没有消耗步数,不需要更新m
再检查字符串中是否有1步就能得到的UCC,即UC和CC,UC可以在末尾插入一个C,CC可以在首部插入一个U,统计UC和CC的数量,统计完之后从字符串中排除,有多少UC和CC,就消耗了多少步的m,更新剩余m的值
再检查是否有2步得到的UCC,即U,C。U可以在末尾插入CC,C可以插入U和C,统计字符串中U和C的数量,一个U或一个C要消耗2步,有多少单个字符就需要消耗两倍字符的步数,更新m的值
最后检查3步得到的UCC,即直接插入UCC,计算剩下的m整除3是多少就行了
m不一定足够经历以上所有的检查,把m尽可能地用完,就可以得到最优的结果
代码实现
直接用正则表达式直观地展示了思路
import re
def solution(m: int, s: str) -> int:
# 统计各种情况的数量
s, nUCC = re.subn(r"UCC", "AAA", s)
s, nUC = re.subn(r"UC", "BB", s)
s, nCC = re.subn(r"CC", "DD", s)
nsg = len(s) - 3 * nUCC - 2 * nUC - 2 * nCC
# 更新结果和步数
res = nUCC
if m > nUC + nCC:
res += nUC + nCC
m -= nUC + nCC
if m // 2 < nsg:
res += m // 2
else:
res += nsg
m -= 2 * nsg
res += m // 3
else:
res += m
return res
if __name__ == '__main__':
print(solution(m=3, s="UCUUCCCCC") == 3)
print(solution(m=6, s="U") == 2)
print(solution(m=2, s="UCCUUU") == 2)
针对贪心的解释
为什么只需要插入操作就能得到最大UCC字串
Prompt
我感觉只需要插入操作就能找到最多的UCC子串,而不需要修改和删除操作,能不能解释一下这是为什么
MarsCode AI
你的直觉是正确的,确实在某些情况下,只需要插入操作就能找到最多的 "UCC" 子串。让我们来详细解释一下为什么插入操作可能是最优的选择。
问题分析
-
插入操作的优势:
- 插入操作可以在字符串的任意位置添加字符,从而更容易形成
"UCC"子串。 - 例如,如果字符串中已经有一个
"U",我们可以通过插入两个"C"来形成一个"UCC"子串。
- 插入操作可以在字符串的任意位置添加字符,从而更容易形成
-
修改和删除操作的劣势:
- 修改操作需要替换现有的字符,这可能会破坏已经存在的
"UCC"子串。 - 删除操作会减少字符串的长度,从而减少形成
"UCC"子串的机会。
- 修改操作需要替换现有的字符,这可能会破坏已经存在的
具体例子
考虑以下字符串 "UCUUCCCCC" 和编辑距离限制 m = 3:
-
插入操作:
- 我们可以在
"U"后面插入两个"C",形成"UCC"。 - 这样,我们可以在
"UCUUCCCCC"中插入两个"C",形成"UCCUCCUCC",包含 3 个"UCC"子串。
- 我们可以在
-
修改和删除操作:
- 如果使用修改或删除操作,可能会破坏已经存在的
"UCC"子串,或者减少字符串的长度,从而减少形成"UCC"子串的机会。
- 如果使用修改或删除操作,可能会破坏已经存在的
结论
在某些情况下,插入操作确实是最优的选择,因为它可以在字符串的任意位置添加字符,从而更容易形成 "UCC" 子串。
复杂度分析
我实际上并不清楚正则表达式的具体实现,我直接让AI帮我进行算法的复杂度分析,我觉得AI应该对python的正则表达式比较清楚
Prompt
计算一下编辑区代码的算法的复杂度
MarsCode AI
复杂度分析
-
正则表达式替换:
re.subn(r"UCC", "AAA", s):这个操作的时间复杂度取决于字符串s的长度n。正则表达式的匹配和替换操作通常是线性时间复杂度,即O(n)。re.subn(r"UC", "BB", s):同上,时间复杂度为O(n)。re.subn(r"CC", "DD", s):同上,时间复杂度为O(n)。
-
字符串长度计算:
len(s):计算字符串长度的时间复杂度为O(1)。
-
编辑距离分配:
- 这部分代码主要是一些简单的算术运算和条件判断,时间复杂度为
O(1)。
- 这部分代码主要是一些简单的算术运算和条件判断,时间复杂度为
总体复杂度
- 正则表达式替换操作的时间复杂度为
O(n)。 - 字符串长度计算和编辑距离分配的时间复杂度为
O(1)。
因此,总体时间复杂度为 O(n),其中 n 是字符串 s 的长度。
空间复杂度
- 正则表达式替换操作会生成新的字符串,因此空间复杂度为
O(n)。 - 其他变量的空间复杂度为
O(1)。
因此,总体空间复杂度为 O(n)。
总结
- 时间复杂度:
O(n),其中n是字符串s的长度。 - 空间复杂度:
O(n)。
可能的其他解法
这道题目一开始我就感觉动态规划可能是一个可以进行的方向,但是时间比较有限,没有进行更深入的探索,通过其他的方式获得了这道题的贪心思路,贪心的代码比较简单明了,实现起来很快,所以就只采用了这种方式完成。豆包AI给的代码框架也是以动态规划的形式给出。应该有其他的博客涉及到这道题动态规划的实现,我的工作暂时进行到了这里,大佬轻喷。