力扣每日一题:650 只有两个键的键盘

题源:只有两个键的键盘

初读这个题,感觉就应该是动态规划,但是找不出状态转移方程,当看到题解之后还是感到非常遗憾,就差一点点。

1. 思路与想法

题目中只有两种操作,copypaste,其中copy必须拷贝当前的所有内容,最终得出nA所需操作的最小次数。

最小次数,copy全部,这两个在一开始就给予了我贪心的感觉,对于nA来说,它期望的上一次操作是n/2处整体复制粘贴过来,n/2n/4…依次类推,就可以得到最小的次数。但很快我发现了上述思想的漏洞,举个例子,如果此时的n15,那就没法通过n/2->n/4这种模式。

15 = 3 * 515虽然不能通过上述的模式得来,但可以通过因数3来操作得来。但很可惜在这里我并没有反应到质因数的层面。

分析到上面,那么问题的实现就简单了:

  • 对于质数,它无法通过任何因数加速它,所以他的操作数就是它本身
  • 对于合数,它可以通过因数来加速操作,但当时苦于想不出动态规划的转移方程,我选择从头到尾构建一个存储[1,n]的数组,数组值为最小操作数。

1.1 算法流程

  • freq[1-n]依次赋值为1-n,修改freq[1] = 0
  • 遍历2-n,对于每次遍历更新其小于等于n的所有倍数的最小次数
  • 全部遍历完成后,返回freq[n]

1.2 代码

def minSteps(n):
    freq = [x for x in range(n + 1)]
    freq[1] = 0
    for i in range(2, n + 1):
        j = 2
        tmp = i * j
        while tmp <= n:
            # 依次更新当前i的倍数
            freq[tmp] = min(freq[i] + j, freq[tmp])
            j += 1
            tmp = i * j
    return freq[n]

2. 官方题解

2.1 动态规划

f[i] 表示打印出iA的最少操作次数。

对于i来说,应先具有jA,使用一次copy操作,再使用若干次paste操作,得到i

因此j应当时i的因数,粘贴的次数为i/j - 1

状态转移方程:
f[i] = min(f[j] + i / j) j是i的因数

def minSteps(n): 
    freq = [0] * (n + 1)
    for i in range(2, n + 1):
        freq[i] = float("inf")
        j = 1
        while j * j <= i:
            if i % j == 0:
                # 状态转移
                freq[i] = min(freq[i], freq[i // j] + j)
                freq[i] = min(freq[i], freq[j] + i // j)
            j += 1
    return freq[n]

2.2 质因数分解

上面动态规划的状态转移方程如下:
f[i] = min(f[j] + i / j) (j是i的因数)

也等价于:
f[i] = min(f[i / j] + j) (j是i的因数)

因此问题转化为:给定初始值n,我们希望通过若干次操作将其变为 1。每次操作我们可以选择n的一个大于 1 的因数j,耗费j 的代价并且将n减少为 n / j。在所有可行的操作序列中,总代价的最小值即为 freq[n]。本质上就是对n进行质因数分解,统计所有质因数的和。

def minSteps(n): 
    ans = 0
    i = 2
    # 分解质因数
    while i * i <= n:
        while n % i == 0:
            ans += i
            n //= i
        i += 1

    if (n > 1):
        ans += n
    return ans
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值