• LeetCode 664. Strange Printer (DP)


    题目:

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

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

    示例 1:

    输入: "aaabbb"
    输出: 2
    解释: 首先打印 "aaa" 然后打印 "bbb"。
    示例 2:

    输入: "aba"
    输出: 2
    解释: 首先打印 "aaa" 然后在第二个位置打印 "b" 覆盖掉原来的字符 'a'。
    提示: 输入字符串的长度不会超过 100。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/strange-printer
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    题解:

    参考讨论区

    https://leetcode.com/problems/strange-printer/discuss/152758/Clear-Logical-Thinking-with-Code

    这是一个区间DP题目

    首先定义  dp[i][j] 表示打印 s[i ... j] 的最小次数,那么枚举 k  dp[i][j] = min(dp[i][k] + dp[k+1][j]) 其中 (i<=k<j)  

    组要注意的是,当 s[i]=s[j] 的时候可以先打印 s[i] 到 s[j] ,所以此时  dp[i][j] = min(dp[i][k] + dp[k+1][j]) - 1 

    class Solution {
        int dp[100][100];
    public:
        int strangePrinter(string s) {
            int n = s.size();
            if (n <= 1) return n;
            memset(dp, -1, sizeof dp);
            return dfs(s, 0, n - 1);
        }
        int dfs(string &s, int l, int r) {
            if (l == r) return 1;
            if (dp[l][r] != -1) return dp[l][r];
            if (l + 1 == r) return dp[l][r] = (s[l] == s[r] ? 1 : 2);
            
            int ans = r - l + 1;
            for (int k = l; k < r; k++) {
                ans = min(ans, dfs(s, l, k) + dfs(s, k + 1, r));
            }
            if (s[l] == s[r]) ans--;
            
            return dp[l][r] = ans;
        }
    };

    作为一个C++废,要特别提示一下,递归时一定一定一定要加上引用,不加就是TLE。

    直接推不递归的话就不会有这种问题了,

    class Solution {
    public:
        int strangePrinter(string s) {
            int n = s.size();
            if (n <= 1) return n;
            int dp[n][n];
            for (int i = n - 1; i >= 0; i--) {
                for (int j = i; j < n; j++) {
                    if (j == i) dp[i][j] = 1;
                    else if (j == i + 1) dp[i][j] = (s[i] == s[j] ? 1 : 2);
                    else {
                        dp[i][j] = j - i + 1;
                        for (int k = i; k < j; k++) {
                            dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
                        }
                        if (s[i] == s[j]) dp[i][j]--;
                    }
                }
            }
            return dp[0][n-1];
        }
    };
  • 相关阅读:
    解决后退网页已过期或刷新询问是否重新提交表单的问题
    一行代码获取中文星期
    单例模式弹出窗体实现
    JAVA实现冒泡排序
    关于BufferedWriter.write超过30W条数据写入过慢问题。
    Ibatis的简单介绍
    链接注入(便于跨站请求伪造)(AppScan扫描结果)
    会话标识未更新(AppScan扫描结果)
    跨站点脚本编制实例(AppScan扫描结果)
    深入Java核心 Java内存分配原理精讲
  • 原文地址:https://www.cnblogs.com/wenruo/p/12461521.html
Copyright © 2020-2023  润新知