There is a strange printer with the following two special requirements:ide
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.ui
Example 1:this
Input: "aaabbb"
Output: 2
Explanation: Print "aaa" first and then print "bbb".
Example 2:spa
Input: "aba"
Output: 2
Explanation: Print "aaa" first and then print "b" from the second place of the string, which will cover the existing c
分析code
这类题目的本质是寻找作某件事在没有特定步骤的情形下总共有多少种实现方法,能够经过遍历全部可能来解决,是一个典型的dp问题。blog
dp[i][j]
表明变成string中从index i 到 index j 部分须要的最少print次数。 那么有:索引
dp[i][i] = 1
: we need 1 turn to paint a single character.dp[i][i + 1]
dp[i][i + 1] = 1
if s.chartAt(i) == s.charAt(i + 1)
dp[i][i + 1] = 2
if s.chartAt(i) != s.charAt(i + 1)
Then we can iteration len
from 2 to possibly n. For each iteration, we iteration start
index from 0 to the farthest possible.ci
dp[start][start + len]
is len + 1
, i.e. print one character each time.index |start ... start + k| |start + k + 1 ... start + len| char | a ... b | | c ... b |
s.charAt(start + k) == s.charAt(start + len)
, we can make it in one turn when we print this character (i.e. b
here)dp[start][start + k] + dp[start + k + 1][start + len] - 1
难理解的部分来了,首选对于 dp[start][start+len] 的最大值确定是len+1, 也就是每次只print一个字符。rem
须要注意的几点是:1. 每次打印一个字符或者是相同字符的序列,这能够推出若是一个字符串里出现了一个不一样的字符,那么至少要为这个字符打印一次。字符串
2. 由于每次的打印能够选择任何位置,能够覆盖原有字符
3. 这是个从无到有,而后再去替换的过程
能够将substring分红两部分,start -> start+k and start+k+1 -> start+len,以索引k做为分割,若是 start+k 处的字符和 start+len初的字符相同,那当咱们在前面打印这个字符b时能够选择一次性打印连续个b,这样在对于dp[start + k + 1][start + len]来讲至关于减小了一次打印b的过程,因此 dp[start][start+len] 就被分解成了子问题 dp[start][start + k] + dp[start + k + 1][start + len] - 1。
代码
class Solution { public int strangePrinter(String s) { if (s == null || s.length() == 0) { return 0; } int n = s.length(); int[][] dp = new int[n][n]; for (int i = 0; i < n; i++) { dp[i][i] = 1; if (i < n - 1) { dp[i][i + 1] = s.charAt(i) == s.charAt(i + 1) ? 1 : 2; } } for (int len = 2; len < n; len++) { for (int start = 0; start + len < n; start++) { dp[start][start + len] = len + 1; for (int k = 0; k < len; k++) { int temp = dp[start][start + k] + dp[start + k + 1][start + len]; dp[start][start + len] = Math.min( dp[start][start + len], s.charAt(start + k) == s.charAt(start + len) ? temp - 1 : temp ); } } } return dp[0][n - 1]; } }