1. 程式人生 > >664. Strange Printer

664. Strange Printer

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

  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.

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子問題嚴格的證明,在討論去也沒發現。。。。