[M数学] lc650. 只有两个键的键盘(dp+思维+质因数)

33 篇文章 2 订阅
13 篇文章 2 订阅

1. 题目来源

链接:650. 只有两个键的键盘

2. 题目解析

十分好的一道题目啊。数学的 O ( n ) O(\sqrt n) O(n ) 解法,和 dp 的 O ( n ) O(n) O(n) 解法都很不错。


方法一:数学+质因数分解

  • 考虑, n = x 1 ∗ x 2 ∗ . . . ∗ x k n=x_1*x_2*...*x_k n=x1x2...xk,我们可视为 x 1 x_1 x1 是先复制一次,然后粘贴 x 1 − 1 x_1-1 x11 次,那么现在的总长度就是:原有的一个 A 加上 x 1 − 1 x_1-1 x11A,也就是共 x_1A,即 x_1 即为总长度。
  • 而针对 x_2,我们也可视为是先将现有总长度复制一次,然后在后面粘贴 x 2 − 1 x_2-1 x21次,那么总长度就是 x 1 + x 1 ( x 2 − 1 ) x_1+x_1(x_2-1) x1+x1(x21) 即为 x 1 ∗ x 2 x_1*x_2 x1x2
  • 同理可得, n = x 1 ∗ x 2 ∗ . . . ∗ x k n=x_1*x_2*...*x_k n=x1x2...xk 只要将 n n n 分解为 x i ≥ 2 x_i \ge 2 xi2正整数的乘积,就能一一对应一种方案。 乘以数字 1 是没有意义的。而数字之和就是操作次数。
  • 再考虑,当乘数中有合数出现时,合数一定可以因式分解。即 x = p ∗ q , x ≥ 2 , p , q > 1 x=p*q, x\ge2,p,q\gt1 x=pq,x2p,q>1,我们仅需证明 p + q ≤ x {p+q}\le x p+qx 即可证明任意合数都可以进行分解,那么最后必然是所有的质数的乘积构成 n n n。即答案(操作次数)即为 n n n 的所有质因子分解式的和。
  • 考虑, ( p − 1 ) ∗ ( q − 1 ) > 1 (p-1)*(q-1)>1 (p1)(q1)>1,因为 p , q > 1 p,q>1 p,q>1,那么 ( p − 1 ) ∗ ( q − 1 ) = p ∗ q − p − q + 1 = x − p − q + 1 > 1 (p-1)*(q-1)=p*q-p-q+1=x-p-q+1>1 (p1)(q1)=pqpq+1=xpq+1>1,那么 x > p + q x\gt p + q x>p+q 恒成立。
  • 这就说明了 n = x 1 ∗ x 2 ∗ . . . ∗ x k n=x_1*x_2*...*x_k n=x1x2...xk 不存在合数,即全为质数。那么由整数唯一分解定理可得 n n n 有唯一质因数分解式,累加和即为答案。

方法二:dp

  • 贪心怕是不行,那就 dp 呗。
  • 状态定义f[i] 表示得到 i 个字符 A 所需的最小操作次数。初始化 f[1]=0。答案 f[n]
  • 状态转移每次考虑最后一个位置是从哪转移过来的。 可以明确的是,多次 copy 情况下,我们只需要枚举 i 的所有约数 j 即可。即 f[i]=f[j]+i/j 意味着 i/j 次中,经历一次复制 f[j] 个,i/j -1 次拷贝到达状态 i。和数学解法的思路大致一样。同理,也可以 f[i]=f[i/j]+j,经历一次复制 f[i/j] 个,拷贝 j-1 次到达状态 i
  • 状态转移剪枝:
    • 在枚举 i 的约数时,显然只需要枚举到根号 i
    • 也可以枚举 i 的时候只考虑 n%i==0的所有的 i 情况即可。但是这个想法比较抽象,不推荐。也懒得去想证明了。

当然这种选不选问题,可以 dfs,但没必要。


  • 时间复杂度 O ( n ) O(\sqrt n) O(n )
  • 空间复杂度 O ( 1 ) O(1) O(1)

dp

class Solution {
public:
    int minSteps(int n) {
        vector<int> f(n + 1, 1e9);
        f[1] = 0;
        for (int i = 2; i <= n; i ++ ) {
            // if (n % i == 0)      // 加上优化效率,剪枝。
            for (int j = 1; j <= i / j; j ++ ) {
                if (i % j == 0) {
                    f[i] = min(f[i], f[j] + i / j);
                    f[i] = min(f[i], f[i / j] + j);
                }
            }
        }

        return f[n];
    }
};

数学

class Solution {
public:
    int minSteps(int n) {
        int res = 0;
        for (int i = 2; i <= n / i; i ++ ) {
            if (n % i == 0) {
                int t = 0;
                while (n % i == 0) n /= i, t ++ ;
                res += i * t;
            }
        }
        if (n > 1) res += n;

        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值