664. 奇怪的打印机|Java 刷题打卡

383 阅读1分钟

本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接

一、题目描述

image.png

二、解题思路

1.动态规划

这种题目想到动态规划很简单,边界条件也比较好理解,但是找到动态转移方程比较有挑战性。
定义dp[][]数组,dp[i][j]为字符区间[i,j]的最少操作数。

  • i==j时,dp[i][j]=1因为只有一个字符(边界条件) i!=j时,怎么计算dp[i][j]呢?
    其实我们可以考虑dp[i][j-1]新增一个字符的情况:
  • s[i]==s[j],dp[i][j]=dp[i][j-1]即字符两端相等。这种情况新增字符是不影响打印次数的。
  • s[j-1]==s[j],dp[i][j]=dp[i][j-1]即新增字符和末尾字符相等。这种情况新增字符是不影响打印次数的。 除开上面两种不影响打印次数的情况,应该怎么算呢?
    可以这么想我们记两部分分别为区间[i,k] 和区间[k+1,j](其中 i≤k<j),dp[i][j]=mink=ij1dp[i][k]+dp[k+1][j]dp[i][j]=min{^{j-1}_{k=i}}dp[i][k]+dp[k+1][j]
    方程有了,那该怎么写呢?或者说根据这个方程能写出代码么?
    我们最终的结果是dp[0][n-1],那么按照我们的方程需要知道dp[0][0...j-1]和dp[1...j-1][j]的值。
  • 因此代码不能从0开始,得从大到小地枚举 i,并从小到大地枚举 j,这样可以保证当计算 dp[i][j] 时,dp[i][k] 和 dp[k+1][j] 都已经被计算过。

时间复杂度分析

3重循环,因此时间复杂度为:

  • O(n^3)

空间复杂度分析

需要二维dp数组,因此空间复杂度为:

  • O(n^2)

三、代码实现

   class Solution {
    public int strangePrinter(String s) {
        int n = s.length();
        int[][] f = new int[n][n];
        for (int i = n - 1; i >= 0; i--) {
            f[i][i] = 1;
            for (int j = i + 1; j < n; j++) {
                if (s.charAt(i) == s.charAt(j)) {
                    f[i][j] = f[i][j - 1];
                }else if(s.charAt(j-1) == s.charAt(j)){
                    f[i][j] = f[i][j - 1];
                } else {
                    int minn = Integer.MAX_VALUE;
                    for (int k = i; k < j; k++) {
                        minn = Math.min(minn, f[i][k] + f[k + 1][j]);
                    }
                    f[i][j] = minn;
                }
            }
        }
        return f[0][n - 1];
    }
}

不晓得我讲清楚了没有,请大家多多指教。
今日打卡结束!