本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
一、题目描述
二、解题思路
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[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];
}
}
不晓得我讲清楚了没有,请大家多多指教。
今日打卡结束!