【Leetcode】664. Strange Printer(配数学证明)

本文解析了LeetCode题目中关于奇怪打印机的解决方案,通过去重和动态规划计算字符串s最少需要的刷写次数。核心算法涉及状态转移方程与最小操作次数的枚举。时间复杂度为O(n^3),空间复杂度为O(n^2)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目地址:

https://leetcode.com/problems/strange-printer/

给定一个长 n n n字符串 s s s,有一个刷子和一个长 n n n的白板,可以每次将任意位置开始的任意长度的段刷成同一个字符,先刷的会被后刷的覆盖。问要刷出 s s s至少要刷多少次。

首先,可以将 s s s去个重,即如果相邻位置字符相等,可以缩成一个,因为无论是什么方案,刷任意其中一个字符,都可以延伸着刷整个相同的一段。

f [ l ] [ r ] f[l][r] f[l][r] s [ l : r ] s[l:r] s[l:r]至少要刷多少次。那么当 l = r l=r l=r的时候, f [ l ] [ r ] = 1 f[l][r]=1 f[l][r]=1;考虑最后一次刷到 s [ l ] s[l] s[l]的那一次,假设这次刷的是 s [ l : k ] s[l:k] s[l:k],那么我们可以先将这次之前刷 s [ l : k ] s[l:k] s[l:k]这部分的操作都变为只刷 s [ k + 1 : ] s[k+1:] s[k+1:]这部分,并且将刷 s [ l : k ] s[l:k] s[l:k]的操作提前为第一次操作,这样显然所得方案的总操作次数不差于原来的方案。所以我们只需要考虑第一次操作就刷了 s [ l ] s[l] s[l]的所有方案。

枚举 k k k,当 k = l k=l k=l时, f [ l ] [ r ] = 1 + f [ l + 1 ] [ r ] f[l][r]=1+f[l+1][r] f[l][r]=1+f[l+1][r];当 k > l k>l k>l时,如果 s [ l ] ≠ s [ k ] s[l]\ne s[k] s[l]=s[k],那么所有第一步刷 s [ i : k ] s[i:k] s[i:k]的方案都可以转化为第一步刷 s [ i : k − 1 ] s[i:k-1] s[i:k1]的方案(因为 s [ l ] ≠ s [ k ] s[l]\ne s[k] s[l]=s[k] s [ k ] s[k] s[k]即使第一步刷了,之后也会覆盖,所以可以第一步刷 s [ l : k − 1 ] s[l:k-1] s[l:k1],操作数也一样),同理,如果 s [ l ] ≠ s [ k − 1 ] s[l]\ne s[k-1] s[l]=s[k1],则可以转为先刷 s [ l : k − 2 ] s[l:k-2] s[l:k2]以此类推。所以所有的方案都可以转化为 s [ l ] = s [ k ] s[l]=s[k] s[l]=s[k]的方案,从而我们只需要枚举这种类型的方案即可。对于 s [ l ] = s [ k ] s[l]=s[k] s[l]=s[k]且第一步刷 s [ l : k ] s[l:k] s[l:k]的方案来说,这种方案都可以对应 f [ l ] [ k − 1 ] f[l][k-1] f[l][k1]的方案(第一步将 s [ l : k − 1 ] s[l:k-1] s[l:k1]刷成 s [ l ] s[l] s[l],之后的所有操作步骤忽略 s [ k ] s[k] s[k]即可),并且对于 f [ l ] [ k − 1 ] f[l][k-1] f[l][k1]的最优方案,它也可以转化为刷 s [ l : k ] s[l:k] s[l:k]的方案(第一步变为刷 s [ l : k ] s[l:k] s[l:k] s [ l ] s[l] s[l]即可,其余操作原样照做),所以此时 f [ l ] [ k ] = f [ l ] [ k − 1 ] f[l][k]=f[l][k-1] f[l][k]=f[l][k1]。后面的部分最少操作次数即为 f [ k + 1 ] [ r ] f[k+1][r] f[k+1][r],所以此时 f [ l ] [ r ] = min ⁡ l < k ≤ r { f [ l ] [ k − 1 ] + f [ k + 1 ] [ r ] } f[l][r]=\min_{l<k\le r}\{f[l][k-1]+f[k+1][r]\} f[l][r]=l<krmin{f[l][k1]+f[k+1][r]}当然 k = r k=r k=r的时候取 f [ k + 1 ] [ r ] = 0 f[k+1][r]=0 f[k+1][r]=0。代码如下:

class Solution {
 public:
  int strangePrinter(string s) {
    int n = 0;
    // 去重
    for (int i = 0; i < s.size(); i++)
      if (!n || s[i] != s[n - 1]) s[n++] = s[i];
    s.resize(n);

    int f[n][n];
    for (int len = 1; len <= n; len++)
      for (int l = 0; l + len - 1 < n; l++) {
        int r = l + len - 1;
        if (len == 1) f[l][r] = 1;
        else {
          f[l][r] = 1 + f[l + 1][r];
          for (int i = l + 1; i <= r; i++)
            if (s[i] == s[l])
              f[l][r] = min(f[l][r], f[l][i - 1] + (i + 1 <= r ? f[i + 1][r] : 0));
        }
      }

    return f[0][n - 1];
  }
};

时间复杂度 O ( n 3 ) O(n^3) O(n3),空间 O ( n 2 ) O(n^2) O(n2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值