作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址:https://leetcode.com/problems/2-keys-keyboard/description/

题目描述

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

  • Copy All: You can copy all the characters present on the notepad (partial copy is not allowed).
  • 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’,问最少经过多少次操作(每次复制/粘贴分别算一次操作),写字板上’A’的个数才能为 n。

注意不能手动敲一个’A’上去,必须复制粘贴!

解题方法

递归

我们先分析递归的方法,递归的思想是由上向下

举个例子:当 n = 36 的时候。

36 = 18 * 2 = 3 * 3 * 2 * 2

如果我们想获得 36 个相同的A,可以先获得 18 个'A',然后复制 1 次,粘贴 1 次,于是就有了 36 个'A'。这就是 36 = 18 * 2 的含义。然后再思考怎么得到 18 个'A',这就是递归。

当起始只有一个'A'的情况下,一种得到36个'A'的方案为:

  1. 复制 1 次,粘贴 2 次,得到 'AAA'
  2. 在上面的基础上,复制 1 次,粘贴 2 次,得到 'AAAAAAAAA'
  3. 在上面的基础上,复制 1 次,粘贴 1 次,得到 18 个 'A'
  4. 在上面的基础上,复制 1 次,粘贴 1 次,得到 36 个 'A'

因为复制和粘贴都算一次操作,所以上面得到了 3 * 3 * 2 * 2 = 36 个'A'

我们可以得出结论:

  1. 如果 n 是素数的话,我们只能通过复制 1 次A,然后粘贴 n - 1 次的方式才能得到 n 个A。总的操作了 n 次。
  2. 如果 n = i * j 的话,最快得到 n 的方式是先得到 i ,复制 1 次,然后再粘贴 j - 1 次,总的就有了 n 个A。总的操作了 minSteps(i) + 1 + j - 1 = minSteps(i) + j = minSteps(i) + n / i 次。

于是就有了递归的解法。该解法是,先让 i 从 2 开始遍历找到 n - 1,判断 i 是不是 n 的因子,如果 i 是 n 的因子,那么总的需要操作 minSteps(i) + n / i次。如果从 2 到 n - 1 没有 n 的因子,那么 n 是个素数,必须操作 n 次。

Python代码如下。

class Solution:
def minSteps(self, n: int) -> int:
if n == 1:
return 0
for i in range(2, n):
if n % i == 0:
return self.minSteps(n // i) + i
return n

素数分解

上面已经给了递归的做法,看了 36 个 'A' 的分解之后,我们发现题目要求的就是 36 的所有素因子之和。素因子是指,该因子不可再次拆分。

为什么非得拆解成 素因子 呢?因为当一个因子还可以分解成更小的因子的时候,那么分解后的结果会更小。

比如 36 = 18 * 2,题目所求的最优结果是 18 + 2 = 20 么?显然不是,因为如果把18 拆开 36 = 3 * 6 * 2,此时复制粘贴的个数只需要 3 + 6 + 2 = 12 次。但这仍然不是最优结果,36 = 3 * 2 * 3 * 2,此时复制粘贴的个数只需要 3 + 2 + 3 + 2 = 10 次。此时已经是最优了。

具体证明就是要证明 m * n > m + n,等价于求 (m - 1)*(n - 1) > 1,当 m 和 n 大于 2 的时候上式永远成立。

至于代码,就是让我们求 n 能拆成哪些素因子。我们让 d 试探是否为因子从 2 开始递增,如果 n 能被 d 整除时,此时的 d 是 n 的一个素因子,求复制粘贴次数的结果中增加 d ;而且如果 d 是个素因子,那么要一次性把 n 中除掉所有的 d。

Python 代码如下。

class Solution:
def minSteps(self, n: int) -> int:
res = 0
d = 2
while n > 1:
while n % d == 0:
res += d
n //= d
d += 1
return res

参考:

https://leetcode-cn.com/problems/2-keys-keyboard/solution/zhi-you-liang-ge-jian-de-jian-pan-by-leetcode/

日期

2018 年 3 月 15 日 —— 雾霾消散,春光明媚
2020 年 5 月 30 日 —— 答辩顺利,心情大好

【LeetCode】650. 2 Keys Keyboard 只有两个键的键盘(Python)的更多相关文章

  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] 650. 2 Keys Keyboard (Medium)

    解法一: 暴力DFS搜索,对每一步进行复制还是粘贴的状态进行遍历. 注意剪枝的地方: 1.当前A数量大于目标数量,停止搜索 2.当前剪贴板数字大于等于A数量时,只搜索下一步为粘贴的状态. Runtim ...

  3. LeetCode 650 - 2 Keys Keyboard

    LeetCode 第650题 Initially on a notepad only one character 'A' is present. You can perform two operati ...

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

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

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

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

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

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

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

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

  8. LC 650. 2 Keys Keyboard

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

  9. [Swift]LeetCode650. 只有两个键的键盘 | 2 Keys Keyboard

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

随机推荐

  1. CPU大小端模式及转换

    通信协议中的数据传输.数组的存储方式.数据的强制转换等这些都会牵涉到大小端问题. CPU的大端和小端模式很多地方都会用到,但还是有许多朋友不知道,今天暂且普及一下. 一.为什么会有大小端模式之分呢? ...

  2. C语言中不用 + 和 - 求两个数之和

    (二)解题 题目大意:不用+或者-实现两个整数的加法 解题思路:不用+或者-,就自然想到位运算,无非就是与或非来实现二进制的加法 首先,我们来看一位二进制的加法和异或运算 A B A&B A^ ...

  3. 学习java 7.28

    学习内容: Applet Applet一般称为小应用程序,Java Applet就是用Java语言编写的这样的一些小应用程序,它们可以通过嵌入到Web页面或者其他特定的容器中来运行,也可以通过Java ...

  4. Vue相关,diff算法。

    1. 当数据发生变化时,vue是怎么更新节点的? 要知道渲染真实DOM的开销是很大的,比如有时候我们修改了某个数据,如果直接渲染到真实dom上会引起整个dom树的重绘和重排,有没有可能我们只更新我们修 ...

  5. 链栈(C++)

    链栈,字面意思,就是用链表来实现一个栈的数据结构. 那么,只需将单链表的头节点当作栈顶,尾节点当作栈底.入栈只需要头插,出栈只需头删即可.所以只需要吧单链表稍微阉割一下就可以得到链式栈了.代码如下 / ...

  6. Linux基础命令---sendmail发送邮件

    sendmail sendmail是postfix中的一个发送邮件的代理程序,它负责发送邮件到远程服务器,并且可以接收邮件.sendmail在发送邮件的时候,默认从标砖输入读取内容,以".& ...

  7. @Value("#{}")与@Value("${}")

    开发过程中,有些配置信息是根据环境的不同而有不同的值.这个时候,我们需要获取配置文件中的值或者spring容器中的值,可以通过@value注解获取相关的值. @Value("#{}" ...

  8. 软件测试人员必备的linux命令

    1 目录与文件操作1.1 ls(初级)使用权限:所有人功能 : 显示指定工作目录下之内容(列出目前工作目录所含之档案及子目录). 参数 : -a 显示所有档案及目录 (ls内定将档案名或目录名称开头为 ...

  9. Android App加固原理与技术历程

    App为什么会被破解入侵 随着黑客技术的普及化平民化,App,这个承载我们移动数字工作和生活的重要工具,不仅是黑客眼中的肥肉,也获得更多网友的关注.百度一下"App破解"就有529 ...

  10. 使用 Nocalhost 开发 Kubernetes 中的 APISIX Ingress Controller

    本文作者:黄鑫鑫 - Nocalhost 项目核心开发者 腾讯云 CODING DevOps 研发工程师.硕士毕业于中山大学数据科学与计算机学院,曾负责过平安云主机及国家超算中心容器云平台等相关业务, ...