leetcode 664. 奇怪的打印机(dp)

题目

有台奇怪的打印机有以下两个特殊要求:

打印机每次只能打印由 同一个字符 组成的序列。
每次可以在任意起始和结束位置打印新字符,并且会覆盖掉原来已有的字符。
给你一个字符串 s ,你的任务是计算这个打印机打印它需要的最少打印次数。

示例 1:

输入:s = “aaabbb”
输出:2
解释:首先打印 “aaa” 然后打印 “bbb”。
示例 2:

输入:s = “aba”
输出:2
解释:首先打印 “aaa” 然后在第二个位置打印 “b” 覆盖掉原来的字符 ‘a’。

解题思路

数组含义

这题的数组的含义应该很容易就看得出来:dp[i][j]代表子串s[i,j]的最少打印次数

状态转移

例如字符串"aba"在计算dp[i][j]=dp[0][2]时,
遍历r(i= 先打印子串s[i…j],然后再将子串s[r+1…j-1]覆盖掉,所以状态转移方程就是 dp[i][j]= Math.min(dp[i][j],dp[i][r]+dp[r+1][j-1]);

  1. 第一步时,打印子串s[i…j]的最少打印次数dp[i][r],因为第一步时,子串s[r+1,j]里面的所有元素都是等于s[r]的(结合题目条件:打印机每次只能打印由 同一个字符组成的序列和s[r]=s[j]可得),所以dp[i][j]=dp[r+1][j]是成立的
  2. 第二步时,将子串s[r+1…j-1]进行打印然后覆盖在第一步的结果上,因此第二步的打印次数就是dp[r+1][j-1]
    将两步的打印次数相加,就是这种情况下的打印次数

初始化

dp[i][i]直接初始化为1,因为一个字符只需要一次打印,其他还没填充的元素均置为最大值。

代码

class Solution {
    public int strangePrinter(String s) {
        int[][] dp = new int[n + 1][n + 1];
        for (int i = 0; i < n; i++) Arrays.fill(dp[i],Integer.MAX_VALUE);
        for (int i = 0; i < n; i++) dp[i][i]=1;
        for (int i = n-1; i >=0; i--) {
            for (int j = i+1; j < n; j++) {
                char cur = s.charAt(j);
                if (cur==s.charAt(j-1))
                dp[i][j]=dp[i][j-1];
                else {
                dp[i][j]=dp[i][j-1]+1; 
                for (int r=j-2;r>=i;r--)
                {
                    if(cur!=s.charAt(r)) continue;
                    dp[i][j]= Math.min(dp[i][j],dp[i][r]+dp[r+1][j-1]);
                }
                }
            }
        }
        return dp[0][n-1];
    }
}

结果

leetcode 664. 奇怪的打印机(dp)_第1张图片

你可能感兴趣的:(leetcode,字符串,动态规划,leetcode,算法,数据结构)