[LeetCode] 2 Keys Keyboard 两键的键盘

简介:

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即可,参见代码如下:

解法一:

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

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

解法二:

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

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

解法三:

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

参考资料:

https://discuss.leetcode.com/topic/97590/java-dp-solution

https://discuss.leetcode.com/topic/97623/loop-best-case-log-n-no-dp-no-extra-space-no-recursion-with-explanation

本文转自博客园Grandyang的博客,原文链接:[LeetCode] 2 Keys Keyboard 两键的键盘

,如需转载请自行联系原博主。

相关文章
|
12月前
【Leetcode -500.键盘行 -504.七进制数】
【Leetcode -500.键盘行 -504.七进制数】
27 0
|
算法 Java C#
【算法千题案例】每日LeetCode打卡——79.键盘行
📢前言 🌲原题样例:键盘行 🌻C#方法:排序遍历 🌻Java 方法:计数 💬总结
【算法千题案例】每日LeetCode打卡——79.键盘行
LeetCode 841:钥匙和房间 Keys and Rooms
题目: ​ 有 N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,...,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。 ​ 在形式上,对于每个房间 i 都有一个钥匙列表 rooms[i],每个钥匙 rooms[i][j] 由 [0,1,...,N-1] 中的一个整数表示,其中 N = rooms.length。
704 0
|
12天前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
2月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
47 6
|
2月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
87 2
|
12天前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
2月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
40 7