引言
本次我将以《最大UCC子串计算》这道题为例,通过这篇文章来解析豆包MarsCode AI刷题的亮点所在;
问题描述
小S有一个由字符 'U' 和 'C' 组成的字符串 SS,并希望在编辑距离不超过给定值 mm 的条件下,尽可能多地在字符串中找到 "UCC" 子串。
编辑距离定义为将字符串 SS 转化为其他字符串时所需的最少编辑操作次数。允许的每次编辑操作是插入、删除或替换单个字符。你需要计算在给定的编辑距离限制 mm 下,能够包含最多 "UCC" 子串的字符串可能包含多少个这样的子串。
例如,对于字符串"UCUUCCCCC"和编辑距离限制m = 3,可以通过编辑字符串生成最多包含3个"UCC"子串的序列。
AI使用
看上去有些复杂,我们让豆包MarsCode AI帮我们解析一下题目:
提交完了发现错误
第二案例错误,我给ai提示
更新完代码发现ai陷入误区,我们给出他们误区,然后再让其写代码
完整代码如下
def solution(m: int, s: str) -> int:
n = len(s)
vis = [False] * n
ret = 0
pos = 0
# 查找现有的 "UCC" 子串
while m >= 0 and pos + 2 < n:
if s[pos] == 'U' and s[pos + 1] == 'C' and s[pos + 2] == 'C':
ret += 1
vis[pos] = vis[pos + 1] = vis[pos + 2] = True
pos += 3
else:
pos += 1
pos = 0
# 尝试通过插入 'C' 来形成 "UCC"
while m > 0 and pos + 1 < n:
if vis[pos] or vis[pos + 1]:
pos += 1
continue
if s[pos] == 'U' and s[pos + 1] == 'C':
ret += 1
m -= 1
vis[pos] = vis[pos + 1] = True
pos += 2
else:
pos += 1
pos = n - 1
# 尝试通过插入 'U' 来形成 "UCC"
while m > 0 and pos - 1 >= 0:
if vis[pos] or vis[pos - 1]:
pos -= 1
continue
if s[pos] == 'C' and s[pos - 1] == 'C':
ret += 1
m -= 1
vis[pos] = vis[pos - 1] = True
pos -= 2
else:
pos -= 1
pos = 0
# 尝试通过插入 'U' 和 'C' 来形成 "UCC"
while m >= 2 and pos < n:
if vis[pos]:
pos += 1
else:
m -= 2
ret += 1
pos += 1
# 剩余的编辑距离可以用来插入 "UCC"
ret += m // 3
return ret
if __name__ == '__main__':
print(solution(3, "UCUUCCCCC") == 3)
print(solution(6, "U") == 2)
print(solution(2, "UCCUUU") == 2)
代码解释
1. 函数定义及初始化
def solution(m: int, s: str) -> int:
n = len(s)
vis = [False] * n
ret = 0
pos = 0
- 定义了一个名为
solution的函数,它接受两个参数:m(整数类型,表示可进行的编辑操作次数)和s(字符串类型,表示给定的字符串),函数返回一个整数。 - 计算输入字符串
s的长度并赋值给n。 - 创建了一个长度为
n的布尔型列表vis,初始值全部为False,用于标记字符串中的字符是否已经在形成 "UCC" 子串的过程中被使用过。 - 初始化变量
ret为 0,用于记录最终可以形成的 "UCC" 子串的数量。 - 初始化变量
pos为 0,用于在字符串中遍历的位置指针。
2. 查找现有的 "UCC" 子串
while m >= 0 and pos + 2 < n:
if s[pos] == 'U' and s[pos + 1] == 'C' and s[pos + 2] == 'C':
ret += 1
vis[pos] = vis[pos + 1] = vis[pos + 2] = True
pos += 3
else:
pos += 1
- 通过一个
while循环来遍历字符串s,循环条件是编辑次数m大于等于 0 且当前位置指针pos加上 2 后仍小于字符串长度n,这样可以保证能够检查到完整的三个字符组成 "UCC" 的情况。 - 在循环内部,如果当前位置
pos、pos + 1和pos + 2所对应的字符依次为 'U'、'C' 和 'C',则说明找到了一个现有的 "UCC" 子串。此时将ret的值加 1,表示找到了一个符合要求的子串,并且将vis列表中对应这三个位置的元素标记为True,表示这三个字符已经被使用过,然后将位置指针pos向后移动 3 位,继续检查后面的字符串。 - 如果当前位置不满足 "UCC" 的条件,则只将位置指针
pos向后移动 1 位,继续检查下一个位置。
3. 尝试通过插入 'C' 来形成 "UCC"
pos = 0
while m > 0 and pos + 1 < n:
if vis[pos] or vis[pos + 1]:
pos += 1
continue
if s[pos] == 'U' and s[pos + 1] == 'C':
ret += 1
m -= 1
vis[pos] = vis[pos + 1] = True
pos += 2
else:
pos += 1
- 首先将位置指针
pos重新置为 0,准备再次遍历字符串。 - 这个
while循环的条件是编辑次数m大于 0 且当前位置指针pos加上 1 后小于字符串长度n,目的是检查是否可以通过插入一个 'C' 来形成 "UCC" 子串。 - 在循环内部,如果
vis[pos]或vis[pos + 1]为True,说明这两个位置的字符已经在之前的操作中被使用过,直接将位置指针pos向后移动 1 位并跳过本次循环的后续操作。 - 如果当前位置
pos的字符为 'U' 且下一个位置pos + 1的字符为 'C',则说明可以通过在这两个字符中间插入一个 'C' 来形成 "UCC" 子串。此时将ret的值加 1,表示找到了一个新的符合要求的子串形成方式,将编辑次数m减 1,表示已经使用了一次编辑操作,并且将vis列表中对应这两个位置的元素标记为True,然后将位置指针pos向后移动 2 位。 - 如果不满足上述插入 'C' 形成 "UCC" 的条件,则将位置指针
pos向后移动 1 位,继续检查下一个位置。
4. 尝试通过插入 'U' 来形成 "UCC"
pos = n - 1
while m > 0 and pos - 1 >= 0:
if vis[pos] or vis[pos - 1]:
pos -= 1
continue
if s[pos] == 'C' and s[pos - 1] == 'C':
ret += 1
m -= 1
vis[pos] = vis[pos - 1] = True
pos -= 2
else:
pos -= 1
- 将位置指针
pos设置为字符串长度n减 1,即从字符串的末尾开始向前遍历。 - 这个
while循环的条件是编辑次数m大于 0 且当前位置指针pos减去 1 后大于等于 0,目的是检查是否可以通过插入一个 'U' 来形成 "UCC" 子串。 - 在循环内部,如果
vis[pos]或vis[pos - 1]为True,说明这两个位置的字符已经在之前的操作中被使用过,直接将位置指针pos向前移动 1 位并跳过本次循环的后续操作。 - 如果当前位置
pos的字符为 'C' 且前一个位置pos - 1的字符为 'C',则说明可以通过在这两个字符前面插入一个 'U' 来形成 "UCC" 子串。此时将ret的值加 1,表示找到了一个新的符合要求的子串形成方式,将编辑次数m减 1,表示已经使用了一次编辑操作,并且将vis列表中对应这两个位置的元素标记为True,然后将位置指针pos向前移动 2 位。 - 如果不满足上述插入 'U' 来形成 "UCC" 的条件,则将位置指针
pos向前移动 1 位,继续检查前一个位置。
5. 尝试通过插入 'U' 和 'C' 来形成 "UCC"
pos = 0
while m >= 2 and pos < n:
if vis[pos]:
pos += 1
else:
m -= 2
ret += 1
pos += 1
- 将位置指针
pos重新置为 0,准备再次遍历字符串。 - 这个
while循环的条件是编辑次数m大于等于 2 且当前位置指针pos小于字符串长度n,目的是检查是否可以通过同时插入一个 'U' 和一个 'C' 来形成 "UCC" 子串。 - 在循环内部,如果
vis[pos]为True,说明这个位置的字符已经在之前的操作中被使用过,直接将位置指针pos向后移动 1 位并跳过本次循环的后续操作。 - 如果
vis[pos]为False,说明这个位置的字符还未被使用过,此时可以通过同时插入一个 'U' 和一个 'C' 来形成 "UCC" 子串。将编辑次数m减 2,表示使用了两次编辑操作,将ret的值加 1,表示找到了一个新的符合要求的子串形成方式,然后将位置指针pos向后移动 1 位。
6. 计算剩余编辑距离可形成的 "UCC" 子串数量
ret += m // 3
- 最后,将剩余的编辑次数
m除以 3 得到的商加到ret上。这是因为每 3 次编辑操作可以插入一个完整的 "UCC" 子串(假设还有足够的位置可以插入),通过这种方式计算出利用剩余编辑次数还能形成的 "UCC" 子串数量,并累加到最终的结果ret中。