leetcode
leetcode 551 ~ 600
四个键的键盘

四个键的键盘

难度:

标签:

题目描述

代码结果

运行时间: 21 ms, 内存: 16.0 MB


/*
 * 四个键的键盘问题:
 * 有四个特殊的键:A、Ctrl-A、Ctrl-C和Ctrl-V。Ctrl-A 选择整个屏幕的文本,Ctrl-C 将选择的文本复制到缓冲区,Ctrl-V 将缓冲区的文本粘贴到屏幕上。
 * 给定一个整数 N,表示按键的次数,编写一个函数在屏幕上显示最多 'A' 字符的个数。
 * 思路:
 * 1. 对于每个按键次数,我们可以有三种选择:按A,Ctrl-A+C+V(选择复制粘贴)。
 * 2. 我们需要找出每个按键次数下最多的A字符数。
 * 3. 使用动态规划的方法来解决这个问题。
 */
import java.util.stream.IntStream;
 
public class FourKeysKeyboardStream {
    public int maxA(int N) {
        // dp[i] 表示按 i 次键时最多能得到多少个 'A'
        int[] dp = new int[N + 1];
        IntStream.rangeClosed(1, N).forEach(i -> {
            // 按 A 键
            dp[i] = dp[i - 1] + 1;
            // 按 Ctrl-A, Ctrl-C, Ctrl-V
            IntStream.range(2, i).forEach(j -> {
                dp[i] = Math.max(dp[i], dp[j - 2] * (i - j + 1));
            });
        });
        return dp[N];
    }
}
 

解释

方法:

这道题采用动态规划的思路求解。我们定义 `dp[n]` 表示 n 次操作能得到的最多 A 的数量。对于每个状态,我们有四种选择:输入 A、复制全部、粘贴、不操作。通过枚举这四种选择,取其中能得到最多 A 的选择作为当前状态的最优解。其中,如果选择复制全部,我们需要枚举复制的起点,即 dp[j-1],其中 j 表示上一次复制全部的位置,然后将剪贴板中的内容粘贴 i-(j+1)+1 次,即可得到 dp[j-1] * (i-(j+1)+1) 个 A。最后返回 dp[n] 即可。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
在动态规划的解决方案中,为什么你选择从 `dp[i-1] + 1` 开始更新 `dp[i]`?这是否意味着每次操作默认先考虑输入一个A?
在动态规划的解决方案中,选择从 `dp[i-1] + 1` 开始更新 `dp[i]` 是因为这是最基本的操作,即每次操作仅仅增加一个 'A'。这意味着每次迭代从最简单的操作(添加一个 'A')开始,然后考虑更复杂的操作(如复制粘贴)。这样做确保了在每个步骤中,我们都从已知的最小操作(即前一步+1个A)开始计算,为后续可能的复制粘贴操作提供基线。
🦆
你的方案中提到,可以选择不操作,但实际代码实现中似乎没有体现出这一操作。请问在哪种情况下,选择不操作是有益的?
实际上,在这个问题的上下文中,选择“不操作”并不是一个有效的策略。提及到‘不操作’可能是在讨论操作的可选性时作为考虑的一部分,但在实现最大化输出的目标时,每一步都应该是有效的操作(输入A、复制或粘贴)。因此,在代码实现中,我们不会看到利用‘不操作’的代码,因为它不会增加产生的'A'的数量,不符合题目的最大化目标。
🦆
在计算 `dp[j - 1] * (i - (j + 1) + 1)` 时,这个公式是如何推导出来的?能否详细解释下其背后的逻辑和意义?
这个公式是基于复制粘贴操作的逻辑推导出来的。在这里,`dp[j-1]` 表示在第 `j-1` 次操作后,所能得到的最大'A'的数量。当在第 `j` 次操作选择复制全部时,从第 `j+1` 次开始到第 `i` 次操作,我们可以选择粘贴。因此,粘贴的次数是 `i - (j+1) + 1`,即从第 `j+1` 次到第 `i` 次的操作次数。因此,从第 `j-1` 次得到的字符数量被复制,然后在后续的每一次操作中被粘贴,所以最终得到的字符总数是 `dp[j-1]` 乘以粘贴次数 `i - (j+1) + 1`。这个公式是计算在选择在第 `j` 次操作后开始复制并粘贴到第 `i` 次所能得到的最大'A'的数量的方法。

相关问题

两个键的键盘

最初记事本上只有一个字符 'A' 。你每次可以对这个记事本进行两种操作:

  • Copy All(复制全部):复制这个记事本中的所有字符(不允许仅复制部分字符)。
  • Paste(粘贴):粘贴 上一次 复制的字符。

给你一个数字 n ,你需要使用最少的操作次数,在记事本上输出 恰好 n 个 'A' 。返回能够打印出 n 个 'A' 的最少操作次数。

 

示例 1:

输入:3
输出:3
解释:
最初, 只有一个字符 'A'。
第 1 步, 使用 Copy All 操作。
第 2 步, 使用 Paste 操作来获得 'AA'。
第 3 步, 使用 Paste 操作来获得 'AAA'。

示例 2:

输入:n = 1
输出:0

 

提示:

  • 1 <= n <= 1000