LeetCode664-奇怪的打印机

题目链接

英文链接:https://leetcode.com/problems/strange-printer/

中文链接:https://leetcode-cn.com/problems/strange-printer/

题目详述

有台奇怪的打印机有以下两个特殊要求:

打印机每次只能打印同一个字符序列。
每次可以在任意起始和结束位置打印新字符,并且会覆盖掉原来已有的字符。
给定一个只包含小写英文字母的字符串,你的任务是计算这个打印机打印它需要的最少次数。

示例 1:

1
2
3
输入: "aaabbb"
输出: 2
解释: 首先打印 "aaa" 然后打印 "bbb"。

示例 2:

1
2
3
输入: "aba"
输出: 2
解释: 首先打印 "aaa" 然后在第二个位置打印 "b" 覆盖掉原来的字符 'a'。

提示: 输入字符串的长度不会超过 100。

题目详解

动态规划。

  • f[i][j] 表示区间 s[i, j] 的最少打印次数。
  • 对于 f[i][j],状态转移如下:
    • 第一种:最差的情况下,s[i] 单独打印,则 f[i][j] = 1 + f[i + 1][j];
    • 第二种:如果 s[i] == s[k], i+ 1 <= k <= j,那么 f[i][j] = min{f[i][j], f[i + 1][k] + f[k + 1][j]},表示将 s[i]s[i + 1][k] 一起打印,f[k + 1][j] 代表 s[k + 1, j] 另外打印。需要注意的是 s[i] == s[j] 时,f[k + 1][j] 越界了,所以数组要多开一位。
  • 初始情况,f[i][i] = 1,表示单个字符打印一次。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class LeetCode_00664 {

public int strangePrinter(String s) {
if (s.isEmpty()) {
return 0;
}
int n = s.length();
int[][] f = new int[n + 1][n + 1];
for (int i = 0; i < n; ++i) {
f[i][i] = 1;
}
for (int i = n - 2; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
f[i][j] = 1 + f[i + 1][j];
for (int k = i + 1; k <= j; ++k) {
if (s.charAt(i) == s.charAt(k)) {
f[i][j] = Math.min(f[i][j], f[i + 1][k] + f[k + 1][j]);
}
}
}
}
return f[0][n - 1];
}
}