题目
思路
- 分析1:
首先我们找UCC的个数,如果是UCC我们根本就不用动。 是否有一种可能原本是UCC,我们进行了一些操作后会有更多的UCC。其实没有,因为 “把UCC中的某个分配给左/右”,效果和“UCC不动直接向左/右插入他们想要的U/C”是一样的。
- 分析2:
什么情况下用删除操作?直觉是删除可以用添加替代。哪种组合需要删除一个才能变成UCC?
UCUC => UCC(删除) 和 UCUC => UCCUC(插入)效果是一样的,甚至*插入更好。因为,多一个C就是多了一个拼成UCC的机会。所有的删除都可以用插入代替。
-
分析3: 什么情况下用修改操作?把一个串修改一次变成UCC,如果改动的是两端,直接插入也可以。如果改的中间,那就是
UUC => UCC(修改),那还不如这样:UUC => UUCC(插入)。所有的修改也都可以用插入代替。 -
分析4
UCC 都找到后,如何找剩下的。我最先想到的是,用UCC将原字符串分割成多个字符串。这样剩下的就是一些“子问题”。但其实不是,因为剩下的串中一定没有完整的 UCC 。所以采用一个等长的新数组 v = [0] * len(s) 记录已组成 UCC 的字符。如果被用到了则 v[i] = 1。
- 分析5:
完整的UCC被找到后,那我们看两两的组合。在两两的组合(UU、UC、CU、CC)中:只有UC和CC是可利用的(只需一次操作)。匹配到则 count += 1 然后 m -= 1。
-
分析6: 剩下的无法利用的单个字符,只能使用
2次添加操作才能让他们组成完整UCC。因此每有一个则count += 1然后m -= 2,注意手里如果不超过2次机会则直接return。 -
分析7:
如果所有的字符都被用完了,而且手里还有超过3个操作次数。则 count += m // 3
代码
def solution(m: int, s: str) -> int:
# PLEASE DO NOT MODIFY THE FUNCTION SIGNATURE
# write code here
n = len(s)
v = [0] * n # 定义访问数组
count = 0
# 统计UCC数量
for i in range(n):
if s[i: i + 3] == 'UCC':
count += 1
v[i: i + 3] = [1, 1, 1]
# 统计UC或者CC数量
for i in range(n):
if m < 1:
return count
if v[i] == 1 or i + 1 < v and v[i+1] == 1:
continue
if (s[i: i + 2] == 'UC' or s[i: i + 2] == 'CC'):
count += 1
v[i: i+2] = [1, 1]
m -= 1
for i in range(n):
if m < 2:
return count
if v[i] == 0:
count += 1
m -= 2
return count + m // 3
if __name__ == '__main__':
print(solution(m=11, s="UUUCCUUUUCCUUUCCU") == 8)
print(solution(m=3, s="UCUUCCCCC") == 3)
print(solution(m=6, s="U") == 2)
print(solution(m=2, s="UCCUUU") == 2)
复杂度
-
时间复杂度: O(n)
-
空间复杂度: O(n)