LeetCode664. Strange Printer

There is a strange printer with the following two special requirements:ide

  1. The printer can only print a sequence of the same character each time.
  2. 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.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

  • The maximum turns for dp[start][start + len] is len + 1, i.e. print one character each time.
  • We can further divide the substring to two parts: start -> start+k and start+k+1 -> start+len. It is something as following:
    index |start ... start + k| |start + k + 1 ... start + len| char | a ... b | | c ... b | 
    • As shown above, if we have s.charAt(start + k) == s.charAt(start + len), we can make it in one turn when we print this character (i.e. b here)
    • This case we can reduce our turns to 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]; } }
相關文章
相關標籤/搜索