Initially on a notepad only one character 'A' is present. You can perform two operations on this notepad for each step:

  1. Copy All: You can copy all the characters present on the notepad (partial copy is not allowed).
  2. Paste: You can paste the characters which are copied last time.

Given a number n. You have to get exactly n 'A' on the notepad by performing the minimum number of steps permitted. Output the minimum number of steps to get n 'A'.

Example 1:

Input: 3
Output: 3
Explanation:
Intitally, we have one character 'A'.
In step 1, we use Copy All operation.
In step 2, we use Paste operation to get 'AA'.
In step 3, we use Paste operation to get 'AAA'.

Note:

  1. The n will be in the range [1, 1000].

这道题只给了我们两个按键,如果只能选择两个按键,那么博主一定会要复制和粘贴,此二键在手,天下我有!!!果然,这道题就是给了复制和粘贴这两个按键,然后给了一个A,目标时利用这两个键来打印出n个A,注意复制的时候时全部复制,不能选择部分来复制,然后复制和粘贴都算操作步骤,问打印出n个A需要多少步操作。对于这种有明显的递推特征的题,要有隐约的感觉,一定要尝试递归和 DP。递归解法一般接近于暴力搜索,但是有时候是可以优化的,从而能够通过 OJ。而一旦递归不行的话,那么一般来说 DP 这个大杀器都能解的。还有一点,对于这种题,找规律最重要,DP 要找出状态转移方程,而如果无法发现内在的联系,那么状态转移方程就比较难写出来了。所以,从简单的例子开始分析,试图找规律:

当n = 1时,已经有一个A了,不需要其他操作,返回0

当n = 2时,需要复制一次,粘贴一次,返回2

当n = 3时,需要复制一次,粘贴两次,返回3

当n = 4时,这就有两种做法,一种是需要复制一次,粘贴三次,共4步,另一种是先复制一次,粘贴一次,得到 AA,然后再复制一次,粘贴一次,得到 AAAA,两种方法都是返回4

当n = 5时,需要复制一次,粘贴四次,返回5

当n = 6时,需要复制一次,粘贴两次,得到 AAA,再复制一次,粘贴一次,得到 AAAAAA,共5步,返回5

通过分析上面这6个简单的例子,已经可以总结出一些规律了,首先对于任意一个n(除了1以外),最差的情况就是用n步,不会再多于n步,但是有可能是会小于n步的,比如 n=6 时,就只用了5步,仔细分析一下,发现时先拼成了 AAA,再复制粘贴成了 AAAAAA。那么什么情况下可以利用这种方法来减少步骤呢,分析发现,小模块的长度必须要能整除n,这样才能拆分。对于 n=6,我们其实还可先拼出 AA,然后再复制一次,粘贴两次,得到的还是5。分析到这里,解题的思路应该比较清晰了,找出n的所有因子,然后这个因子可以当作模块的个数,再算出模块的长度 n/i,调用递归,加上模块的个数i来更新结果 res 即可,参见代码如下:

解法一:

class Solution {
public:
int minSteps(int n) {
if (n == ) return ;
int res = n;
for (int i = n - ; i > ; --i) {
if (n % i == ) {
res = min(res, minSteps(n / i) + i);
}
}
return res;
}
};

下面这种方法是用 DP 来做的,我们可以看出来,其实就是上面递归解法的迭代形式,思路没有任何区别,参见代码如下:

解法二:

class Solution {
public:
int minSteps(int n) {
vector<int> dp(n + , );
for (int i = ; i <= n; ++i) {
dp[i] = i;
for (int j = i - ; j > ; --j) {
if (i % j == ) {
dp[i] = min(dp[i], dp[j] + i / j);
}
}
}
return dp[n];
}
};

上面的解法其实可以做一丢丢的优化,在遍历j的时候,只要发现了第一个能整除i的j,直接可以用 dp[j] + i/j 来更新 dp[i],然后直接 break 掉j的循环,之后的j就不用再考虑了,可能是因为因数越大,其需要的按键数就越少吧,参见代码如下:

解法三:

class Solution {
public:
int minSteps(int n) {
vector<int> dp(n + );
for (int i = ; i <= n; ++i) {
dp[i] = i;
for (int j = i - ; j > ; --j) {
if (i % j == ) {
dp[i] = dp[j] + i / j;
break;
}
}
}
return dp[n];
}
};

下面我们来看一种省空间的方法,不需要记录每一个中间值,而是通过改变n的值来实时累加结果res,参见代码如下:

解法四:

class Solution {
public:
int minSteps(int n) {
int res = ;
for (int i = ; i <= n; ++i) {
while (n % i == ) {
res += i;
n /= i;
}
}
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/650

类似题目:

4 Keys Keyboard

Broken Calculator

参考资料:

https://leetcode.com/problems/2-keys-keyboard/

https://leetcode.com/problems/2-keys-keyboard/discuss/105899/Java-DP-Solution

https://leetcode.com/problems/2-keys-keyboard/discuss/105928/JavaC%2B%2B-Clean-Code-with-Explanation-4-lines-No-DP

https://leetcode.com/problems/2-keys-keyboard/discuss/105897/Loop-best-case-log(n)-no-DP-no-extra-space-no-recursion-with-explanation

 

[LeetCode] 2 Keys Keyboard 两键的键盘的更多相关文章

  1. [LeetCode] 650. 2 Keys Keyboard 两键的键盘

    Initially on a notepad only one character 'A' is present. You can perform two operations on this not ...

  2. [LeetCode] 4 Keys Keyboard 四键的键盘

    Imagine you have a special keyboard with the following keys: Key 1: (A): Print one 'A' on screen. Ke ...

  3. [LeetCode] 651. 4 Keys Keyboard 四键的键盘

    Imagine you have a special keyboard with the following keys: Key 1: (A): Print one 'A' on screen. Ke ...

  4. LeetCode 4 Keys Keyboard

    原题链接在这里:https://leetcode.com/problems/4-keys-keyboard/description/ 题目: Imagine you have a special ke ...

  5. Leetcode 之 Keys Keyboard

    1. 2 Keys Keyboard 先把dp的最小不走都设置为无穷大(Integer.MAX_VALUE),初始化条件:dp[0] = dp[1] = 0,状态转移方程为dp[i] = Math.m ...

  6. Leetcode 650.只有两个键的键盘

    只有两个键的键盘 最初在一个记事本上只有一个字符 'A'.你每次可以对这个记事本进行两种操作: Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的). Past ...

  7. 【LeetCode】650. 只有两个键的键盘

    只有两个键的键盘 最初在一个记事本上只有一个字符 'A'.你每次可以对这个记事本进行两种操作: 1.Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的). 2. ...

  8. Java实现 LeetCode 650 只有两个键的键盘(递归 || 数学)

    650. 只有两个键的键盘 最初在一个记事本上只有一个字符 'A'.你每次可以对这个记事本进行两种操作: Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的). ...

  9. LeetCode解题报告—— 2 Keys Keyboard & Longest Palindromic Substring & ZigZag Conversion

    1. Longest Palindromic Substring Given a string s, find the longest palindromic substring in s. You ...

随机推荐

  1. Be Better , Be Better

    Be Better! 这不是一道题,只是我的flag.初三寒假,一个本应该对着计算机翻天覆雨的假期,我在鬼班撸高中课...其实感触是从初中课得来的.有些事,以前我说是我不懂,现在我不说不是我不懂.Ju ...

  2. java数组排序,并将数组内的数据求和

    java数据编列并求和,江湖我狼哥,人狠话不多,直接上代码! import java.util.Arrays; public class Intarry { public static void ma ...

  3. Spring MVC的handlermapping之SimpleUrlHandlerMapping初始化

    前面信息同BeanNameUrlHandlerMapping,这里不再过多分析,详情请看 :Spring MVC的handlermapping之BeanNameUrlHandlerMapping初始化 ...

  4. [日常] NOIP 2017滚粗记

    突然挑了这么个滑稽的时间补了游记... (成绩日常延时再加上人太菜估计基本上就是颓废记录) 然而文化课太废可能会被强制退役QAQ所以先补了再说吧 day0 一大早被老姚交代了个开十一机房门的任务... ...

  5. 第二次作业评分可能要 delay 一些

    各位同学,因为我现在在出差,昨天刚刚到旧金山,加上倒时差,所以这次作业我处理得会更慢一些,希望谅解. 另外,博客园的邮件通知邮件好多都进垃圾箱了,所以如果你有什么问题我没回且你关心的,请给我写邮件:j ...

  6. Beta No.7

    今天遇到的困难: 构造新适配器的时候出现了某些崩溃的问题 ListView监听器有部分的Bug 今天完成的任务: 陈甘霖:完成相机调用和图库功能,完成阿尔法项目遗留下来的位置调用问题,实现百度定位 蔡 ...

  7. 201621123057 《Java程序设计》第5周学习总结

    1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 接口,interface,implements,方法签名,has-a,Comparable,Comparator. 1.2 尝试 ...

  8. Linux学习--线程概念

    线程 我们知道 ,进程在各自独立的地址空间中运行,进程之间共享数据需要用mmap或者进程间通信机制,本节我们学习如何在一个进程的地址空间中执行多个线程.有些情况需要在一个进程中同时执行多个控制流程,这 ...

  9. mvc架构模式概念

    MVC模式是"Model-View-Controller"的缩写,中文翻译为"模式-视图-控制器".MVC应用程序总是由这三个部分组成.Event(事件)导致C ...

  10. 【iOS】swift 让程序挂起后,能在后台继续运行任务

    1,程序的挂起和退出 由于iOS设备资源有限.当用户点击了home键,或者另一个应用程序启动了.那么原先那个程序便进入后台被挂起,不是退出,只是停止执行代码,同时它的内存被锁定.当应用程序恢复时,它会 ...