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,k,因为i..k之间可能会与后面的k+1..j发生关联,即最佳的dp[i][j]在处理i..k中某一个的时候正好把k+1..j中的某个数给处理掉了,但是我们不知道最佳的dp[i][j]在i..k哪个位置与k+1..j的哪个位置联系在了一起。
那我们就用k表示处理到第k个位置的时候,正好把j位置的也一并处理掉了
(1)为什么是最右边的j位置:因为如果是中间位置,k总会遍历到的
(2)最右边要留出来,因为计算距离为d时,只能用距离为0..d-1的dp数组
class Solution {
public int strangePrinter(String s) {
int n = s.length();
if(n == 0) return 0;
int[][] dp = new int[n][n];
for(int i=0; i<n; i++) dp[i][i] = 1;
char[] cs = s.toCharArray();
for(int d=1; d<n; d++) {
for(int i=0; i+d<n; i++) {
dp[i][i+d] = d+1;
for(int j=i+1; j<=i+d; j++) {
int t = dp[i][j-1] + dp[j][i+d];
if(cs[j-1] == cs[i+d]) t--;
dp[i][i+d] = Math.min(dp[i][i+d], t);
}
}
}
return dp[0][n-1];
}
或者换个思路:
1. 如果把某个位置k的刷好了,那肯定就不要再改动这个k位置了,因为改动需要1次粉刷,可定就不是最优的了
2. 既然不能动以及刷好了的,那我们就可以吧原问题divide成2个互相独立的问题
3. 而且在刷k的时候,可能也可以把后面的顺带处理掉,至于为什么是最后这个数,参考上面的分析
class Solution:
def strangePrinter(self, s):
"""
:type s: str
:rtype: int
"""
s = ''.join(a for a,b in zip(s, '#'+s) if a!=b)
n = len(s)
if n==0: return 0
dp = [[999999 for _ in range(n)] for _ in range(n)]
for i in range(n): dp[i][i]=1
for dist in range(1, n):
for left in range(0, n-dist):
right = left + dist
for k in range(left, right):
cur = dp[left][k]+dp[k+1][right]
if s[k]==s[right]: cur -= 1
dp[left][right] = min(dp[left][right], cur)
return dp[0][n-1]
s=Solution()
print(s.strangePrinter('aaabbb'))
print(s.strangePrinter('aba'))
至于DP子问题严格的证明,在讨论去也没发现。。。。