力扣 664. 奇怪的打印机
力扣 . 奇怪的打印机
题目描述
有台奇怪的打印机有以下两个特殊要求:
打印机每次只能打印由 同一个字符 组成的序列。
每次可以在任意起始和结束位置打印新字符,并且会覆盖掉原来已有的字符。
给你一个字符串 ,你的任务是计算这个打印机打印它需要的最少打印次数。
示例 1:
输入:
输出:
解释:首先打印 然后打印 。
示例 2:
输入:
输出:
解释:首先打印 然后在第二个位置打印 覆盖掉原来的字符 。
提示:
- 由小写英文字母组成
解决方案 : 动态规划
我们可以使用 动态规划 解决本题
一、状态表示
令 表示打印完成区间 的 最少操作数
为什么这样设计状态?
状态的设计一般是根据 尝试 和 经验
经验:以前做过类似的题,知道状态该怎么设计。
尝试:才用最简单的一维状态表示来描述,如果发现行不通,再转为二维状态表示,实在不行再三维状态表示。
-
尝试用一维状态表示它::结束位置为时的最少操作数
这样表示行不行呢?不行呗!为啥呢?因为人家题目说了,可以从任意位置 开始、结束,你这里只记录了结束,开始的概念丢失了。 -
尝试用二维状态表示它:从开始到结束的最少操作次数
状态设计原则
- 状态设计是不是最终能包含答案
- 通过简单枚举可以找出正确答案
二、状态转移方程
当我们尝试计算出 时,需要考虑两种情况:
-
即 区间两端的字符相同时,那么当我们打印左侧字符 时,可以顺便打印右侧字符 ,这样我们即可忽略右侧字符对该区间的影响,只需要考虑如何尽快打印完区间 即可,即此时有 。 -
即区间两端的字符不同,那么我们需要分别完成该区间的左右两部分的打印。我们记两部分分别为区间 和区间 (其中),此时
注意:这里的取值范围值得仔细思考,因为是划分成两段,设第一段结束点为,第二段的开始点为,则有,即:
时是成立的,表示只有点打印一次,从开始至打印其它的(不一定是同一种噢~)
总结状态转移方程为:
三、边界与答案
边界条件为 ,对于长度为 的区间,最少打印 次。最后的答案为。
四、枚举的顺序
注意到 的计算需要用到 和 (其中
)。 为了保证动态规划的计算过程满足无后效性,在实际代码中,我们需要 改变动态规划的计算顺序,从大到小地枚举 ,并从小到大地枚举 ,这样可以保证当计算 时, 和 都已经被计算过。
复杂度分析
时间复杂度:,其中 是字符串的长度。
空间复杂度:,其中 是字符串的长度。我们需要保存所有 个状态。
实现代码
class Solution {
const int INF = 0x3f3f3f3f;
public:
int f[110][110];
int strangePrinter(string s) {
int n = s.size();
//预求最小,先设最大
memset(f, 0x3f, sizeof f);
//1.因为f[i][j]依赖于f[i][k],f[k+1][j],其中k+1>i的,为了保证无后效性,需要在计算f[i]之前准备好f[k+1],所以,倒序枚举i
//2.因为f[i][j]依赖于f[i][k],f[k+1][j],f[i][j-1],k<j的,所以在计算f[i][j]之前,f[i][k],f[i][j-1]需要提前准备好,正序枚举j
//倒序枚举i,从字符串最后一位出发,向0前进
for (int i = n - 1; i >= 0; i--) {
//初始状态,每个起点出发,到自己结束,只包含一个字符的情况就是最简单的基本情况,此时打印次数为1,可以确定,其它无法确定的,靠状态转移方程进行转移即可填充数据
f[i][i] = 1;
//正序枚举j,由于i==j,也就是一个子串中只有一个字符的情况上面已经处理过了,这里只需要处理j>i的即可,并且,j的极限值是n-1, 因为j的字符串的长度上限
for (int j = i + 1; j < n; j++) {
if (s[i] == s[j])
f[i][j] = f[i][j - 1];
else {
for (int k = i; k < j; k++)//注意思考与理解k的范围,尤其是带等号和不带等号的地方
f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j]);
}
}
}
//范围i=0,j=n-1的最小打印次数就是答案
return f[0][n - 1];
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2019-11-08 Clion中配置使用更大的栈(防止开大一点的数组异常)
2018-11-08 Update openssh7.9 on centos6
2017-11-08 关于云平台中OFFICE预览与视频预览的解决办法