该题解采用了动态规划的思路。首先对原字符串进行预处理,去除连续重复的字符。然后使用记忆化搜索来求解最少打印次数。dp(i, j) 表示打印子串 s[i:j] 所需的最少次数。如果 s[i] 和 s[j-1] 相同,则可以直接忽略最后一个字符。否则,枚举 s[i:j] 中间与 s[j-1] 相同的字符作为分割点,将原问题分解为两个子问题,取各子问题的最优解,然后相加得到原问题的最优解。通过记忆化搜索避免了重复计算。
时间复杂度: O(n^3)
空间复杂度: O(n^2)
class Solution:
def strangePrinter(self, s: str) -> int:
# 预处理,去除连续重复的字符
stack = []
for i, c in enumerate(s):
if not stack or stack[-1] != c:
stack.append(c)
s = ''.join(stack)
# 记录每个字符最后一次出现的位置
last_seen = [-1] * 26
prev = [-1] * len(s)
for i, c in enumerate(s):
prev[i] = last_seen[ord(c) - ord('a')]
last_seen[ord(c) - ord('a')] = i
@cache
def dp(i: int, j: int) -> int:
if i >= j - 1:
return j - i
if s[i] == s[j - 1]:
return dp(i, j - 1)
min_ = 100
k = j - 1
while k > i: # 只在和最后字符相同的字符下标分割
min_ = min(dp(i, k) + dp(k, j), min_)
k = prev[k]
return min_
return dp(0, len(s))