【Lintcode】975. 2 Keys Keyboard(配数学证明)

题目地址:

https://www.lintcode.com/problem/2-keys-keyboard/description

有一个笔记本,上面写了一个字符 A A A,每次可以执行下面两个操作之一:
1、复制笔记本上已经存在的所有字符;
2、粘贴上一次复制过的字符。
问要让笔记本上恰好出现 n n n A A A至少需要多少次操作。

法1:动态规划。设 f [ n ] f[n] f[n]为恰好出现 n n n A A A至少需要多少次操作。如果 n n n是素数,那么执行第二个步骤的时候,”上一次“复制过的字符数量一定是 1 1 1,否则的话,就会使得 n n n有非 1 1 1的约数,矛盾。所以如果 n n n是素数,那么需要的操作次数就是 n n n;考虑 n n n的最大真因子 k k k,我们接下来证明: f [ n ] = f [ k ] + n / k f[n]=f[k]+n/k f[n]=f[k]+n/k也就是说,如果素因子分解 n = p 1 s 1 p 2 s 2 . . . p t s t n=p_1^{s_1}p_2^{s_2}...p_t^{s_t} n=p1s1p2s2...ptst,那么 f [ n ] = p 1 s 1 + p 2 s 2 + . . . + p t s t f[n]=p_1s_1+p_2s_2+...+p_ts_t f[n]=p1s1+p2s2+...+ptst数学归纳法。当 n = 1 , 2 , 3 n=1,2,3 n=1,2,3的时候显然正确。假设结论对于 n − 1 n-1 n1是成立的,对于 n n n,假设最后一次执行copy的时候是笔记本上有 i i i个字符的时候,那么总次数应该是 f [ i ] + n / i f[i]+n/i f[i]+n/i,设 i = p 1 r 1 p 2 r 2 . . . p t r t i=p_1^{r_1}p_2^{r_2}...p_t^{r_t} i=p1r1p2r2...ptrt,其中 r j ≤ s j r_j\le s_j rjsj,所以 f [ i ] + n / i = p 1 r 1 + p 2 r 2 + . . . + p t r t + p 1 s 1 − r 1 p 2 s 2 − r 2 . . . p t s t − r t f[i]+n/i=p_1r_1+p_2r_2+...+p_tr_t+p_1^{s_1-r_1}p_2^{s_2-r_2}...p_t^{s_t-r_t} f[i]+n/i=p1r1+p2r2+...+ptrt+p1s1r1p2s2r2...ptstrt也就是要证明 p 1 ( s 1 − r 1 ) + p 2 ( s 2 − r 2 ) + . . . + p t ( s t − r t ) ≤ p 1 s 1 − r 1 p 2 s 2 − r 2 . . . p t s t − r t p_1(s_1-r_1)+p_2(s_2-r_2)+...+p_t(s_t-r_t)\le p_1^{s_1-r_1}p_2^{s_2-r_2}...p_t^{s_t-r_t} p1(s1r1)+p2(s2r2)+...+pt(strt)p1s1r1p2s2r2...ptstrt s m − r m = x m ≥ 0 s_m-r_m=x_m\ge 0 smrm=xm0,即要证明: p 1 x 1 + . . . + p t x t ≤ p 1 x 1 . . . p t x t p_1x_1+...+p_tx_t\le p_1^{x_1}...p_t^{x_t} p1x1+...+ptxtp1x1...ptxt这可以由数学归纳法证明,当 t = 1 t=1 t=1的时候, p 1 x 1 ≤ p 1 x 1 p_1x_1\le p_1^{x_1} p1x1p1x1相当于要证 g ( x 1 ) = p 1 x 1 − 1 − x 1 ≥ 0 g(x_1)=p_1^{x_1-1}-x_1\ge 0 g(x1)=p1x11x10 x 1 = 0 , 1 x_1=0,1 x1=0,1的时候都是对的,求导得 g ′ ( x 1 ) = p 1 x 1 − 1 ln ⁡ p 1 − 1 ≥ 0 , x 1 ≥ 2 g'(x_1)=p_1^{x_1-1}\ln p_1-1\ge 0,x_1\ge 2 g(x1)=p1x11lnp110,x12所以 g ( x 1 ) ≥ 0 g(x_1)\ge 0 g(x1)0恒成立,所以 t = 1 t=1 t=1的时候成立;假设对于 t − 1 t-1 t1成立,则由归纳假设知 p 1 x 1 + . . . + p t x t ≤ p 1 x 1 . . . p t − 1 x t − 1 + p t x t p_1x_1+...+p_tx_t\le p_1^{x_1}...p_{t-1}^{x_{t-1}}+p_tx_t p1x1+...+ptxtp1x1...pt1xt1+ptxt即要证明 h ( x t ) = p 1 x 1 . . . p t − 1 x t − 1 ( p t x t − 1 ) − p t x t ≥ 0 h(x_t)=p_1^{x_1}...p_{t-1}^{x_{t-1}}(p_t^{x_t}-1)-p_tx_t\ge 0 h(xt)=p1x1...pt1xt1(ptxt1)ptxt0,当 x t = 0 , 1 x_t=0,1 xt=0,1的时候都成立,求导得 h ′ ( x t ) = p 1 x 1 . . . p t − 1 x t − 1 p t x t ln ⁡ p t − p t ≥ 0 , x t ≥ 2 h'(x_t)=p_1^{x_1}...p_{t-1}^{x_{t-1}}p_t^{x_t}\ln p_t-p_t\ge 0, x_t\ge 2 h(xt)=p1x1...pt1xt1ptxtlnptpt0,xt2所以 h ( x t ) ≥ 0 h(x_t)\ge 0 h(xt)0,由数学归纳法, p 1 x 1 + . . . + p t x t ≤ p 1 x 1 . . . p t x t p_1x_1+...+p_tx_t\le p_1^{x_1}...p_t^{x_t} p1x1+...+ptxtp1x1...ptxt成立,所以对于任意的 i ∣ n i|n in,都有 f [ i ] + n / i ≥ f [ k ] + n / k f[i]+n/i\ge f[k]+n/k f[i]+n/if[k]+n/k,所以当 i i i n n n的最大真因子的时候操作次数最少。所以算法成立。代码如下:

public class Solution {
    /**
     * @param n: The number of 'A'
     * @return: the minimum number of steps to get n 'A'
     */
    public int minSteps(int n) {
        // Write your code here
        int[] dp = new int[n + 1];
    
        for (int i = 2; i <= n; i++) {
            dp[i] = i;
            for (int j = i / 2; j >= 1; j--) {
            	// 找到最大真因子了
                if (i % j == 0) {
                    dp[i] = dp[j] + i / j;
                    break;
                }
            }
        }
        
        return dp[n];
    }
}

时空复杂度 O ( n ) O(n) O(n)

注解:
这里的动态规划的意味看起来并不浓厚。实际上

if (i % j == 0) {
	dp[i] = dp[j] + i / j;
	break;
}

这一句,如果改为:

if (i % j == 0) {
	dp[i] = Math.min(dp[i], dp[j] + i / j);
}

那么按照最后一步分类的意味会更加明显(这里是按照多少个字符的时候最后一次执行copy来分类的),更有动态规划的味道。只不过可以用数学证明,数到最大真因子的时候就能得到最优解而break出来了而已。

法2:根据上面的公式 f [ n ] = p 1 s 1 + p 2 s 2 + . . . + p t s t f[n]=p_1s_1+p_2s_2+...+p_ts_t f[n]=p1s1+p2s2+...+ptst可以直接计算。代码如下:

public class Solution {
    /**
     * @param n: The number of 'A'
     * @return: the minimum number of steps to get n 'A'
     */
    public int minSteps(int n) {
        // Write your code here
        int res = 0;
        for (int i = 2; i <= n; i++) {
        	// 累加s个p
            while (n % i == 0) {
                res += i;
                n /= i;
            }
        }
        
        return res;
    }
}

时间复杂度 ∑ s i \sum{s_i} si,空间 O ( 1 ) O(1) O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值