DP记录
四字键盘
即A,Crtl+A,Crtl+C,Crtl+V四种键盘,使用它们在一个啥也没有的空界面上在指定的N次操作下得到最多的字符,上次笔试遇到的打字店老板题目是类似的,只不过他把Crtl和后键分开了。
部分内容取自labuladong:
https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/dong-tai-gui-hua-zhi-si-jian-jian-pan#di-er-zhong-si-lu
对于不同的DP状态定义有不同的解法
对于不同的DP状态定义有不同的解法,当然其时间、空间复杂度也不相同;这道题有两种dp状态的定义方法:
方法1:传统方法,暴力列举所有状态
即dp[i][j][k] ;这里i= 剩余操作数;j = 屏幕中已有的字符个数; k = 剪贴板中的字符数;这种定义好在方便想出,构造也比较简单,状态之间的转移也很容易获得;Base case也是很容易得到的;
//base case
dp[0][j][k] = j;
状态转移
dp[i][j][k] = max(dp[i-1][j+1][k],dp[i-1][j+k][k],dp[i-2][j][k]);
这个方法的时间复杂度是n^3×函数复杂度;
方法2:“贪心”+dp
我们可以思考一下后想到,或者从N=1,到N=20试一试,发现N较小时,单个打字符是比较划算的,在N较大时,使用C+V是比较划算的。所以要将这两个进行比较,取其最大者。重新定义动态规划dp的定义:
dp【i】= 使用i此操作能获得的最大字符数
此时的base case
dp[0] = 0;
dp[1] = 1;
状态转移方法:假设从j开始粘贴字符了,那么,第j-2次操作为C+A,j-1次操作为C+C,第j次就是C+V了。
for (int i = 1; i <= N; i++) {
// 按 A 键
dp[i] = dp[i - 1] + 1;
for (int j = 2; j < i; j++) {
// 全选 & 复制 dp[j-2],连续粘贴 i - j 次
// 屏幕上共 dp[j - 2] * (i - j + 1) 个 A
dp[i] = Math.max(dp[i], dp[j - 2] * (i - j + 1));
}