664. Strange Printer

class Solution {
public:
    int dp[100][100];
    int dfs(const string &s, int i,int j)
    {
        if(i>j)return 0;
        if(dp[i][j])return dp[i][j];
        dp[i][j]=dfs(s,i,j-1)+1;
        for(int k=i;k<j;++k)
        {
            if(s[k]==s[j])dp[i][j]=min(dp[i][j],dfs(s,i,k)+dfs(s,k+1,j-1));
        }
        return dp[i][j];
    }
    int strangePrinter(string s) {
        if(s.empty())return 0;
        return dfs(s,0,s.size()-1);
    }
};

  

1

我刚开始的思路是, 相邻的字符如果相同就去重, 然后循环 0 到 n, 首尾相等的话就不用额外打印; 

例如  aaabbbaaa  先去重变为  aba , 循环第一个, a 打印一次,  第二个b 打印一次,  第三个a 发现和第一个相同, 不用打印;  然后提交时发现有些case没有通过测试;

后来总结了下, 我漏掉了回文的情况,  我发现这题用回文思路也能做, 因为打印回文的话, 回文总长度是n, 是不是最多n/2+1次就可以了,  例如  abcba=3次   abccba=3次  aaaa=1次, 不过我也懒得去实现回文算法来做比较了.

2

上面贴的答案是discussion讨论区的答案, 很标准的dfs+dp 解法,  代码很清晰, 几乎不需要解释, 

大致思路就是 每新增一个字符, 尽可能想办法不要额外次数去打印, 那么不打印的办法就是看有没有办法和前面已经打印过得字符"合并",  这里极端的情况就是上面说到的回文啦

打印字符串第i个位置到第j个位置需要的次数  =  dp[i][j];

dp[i][j] = min (dp[i][j-1]+1, dp[i][k]+dp[k+1][j-1])   i<k<j;   

min左边的意思是不能合并, 只能再打印一次,  右边的意思是  找到一个位置k,  符合 i<k<j,  使得  i到k  这部分  +   k+1到j 这部分 之和最小

原文地址:https://www.cnblogs.com/lychnis/p/9247920.html