题目:
There is a strange printer with the following two special requirements:
- The printer can only print a sequence of the same character each time.
- At each turn, the printer can print new characters starting from and ending at any places, and will cover the original existing characters.
Given a string consists of lower English letters only, your job is to count the minimum number of turns the printer needed in order to print it.
Example 1:
Input: "aaabbb" Output: 2 Explanation: Print "aaa" first and then print "bbb".
Example 2:
Input: "aba" Output: 2 Explanation: Print "aaa" first and then print "b" from the second place of the string, which will cover the existing character 'a'.
Hint: Length of the given string will not exceed 100.
思路:
我们定义dp[i][j]表示打印区间[i,j]内的子字符串所需要的最小turn的个数。那么对于dp[left][right]而言,我们首先将其初始化为len = right - left + 1,也就是每次都打印一个单独的字符。然后判断在[left,right]中,是否存在一个left <= k < right,其中s[left] == s[k + 1]或者s[k] == s[right],如果这样,意味着我们可以少一次turn。为什么呢?
我们以abcdaefg为例,dp[0][7]首先被初始化为8,表示我们每次只打印一个字符,一共需要8次turn。这样dp[0][4] == dp[5][8] == 4,意味着我们先打印abcd,然后打印aefg。然而我们发现s[0] == s[4],那么我们的一个更优的选择就是:先从s[4]打印到s[0],然后再从s[1]打印到[3],这样在从s[0]到s[4]中间,我们原来需要turn5次,现在就只需要turn4次了。由于我们让len从小到大不断循环,所以当我们计算dp[left][right]的时候,所有长度小于right - left + 1的dp最优值都已经被计算出来了,所以可以保证最终的dp[0][length - 1]就是最终我们需要的结果。
算法的时间复杂度是O(n^3),空间复杂度是O(n^2)。
代码:
class Solution {
public:
int strangePrinter(string s) {
int length = s.length();
if (length == 0) {
return 0;
}
std::vector<std::vector<int>> buffer(length, std::vector<int>(length, 0));
for (int len = 1; len <= length; ++len) {
for (int left = 0; left < length - len + 1; ++left) {
int right = left + len - 1;
buffer[left][right] = len; // print one char at a time
for (int k = left; k < right; ++k) { // try print [left, k] && [k+1, right]
int steps = buffer[left][k] + buffer[k+1][right];
if (s[left] == s[k+1] || s[k] == s[right]) {
--steps;
}
buffer[left][right] = std::min(buffer[left][right], steps);
}
}
}
return buffer[0][length - 1];
}
};