ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

每日一题_650. 只有两个键的键盘

2021-09-19 17:01:06  阅读:182  来源: 互联网

标签:int 键盘 次数 k1 粘贴 650 得到 一题 dp


每日一题_650. 只有两个键的键盘

leetcode

题目:
在这里插入图片描述
题意分析:
题目的意思是说,初始情况下只有一个A的情况下,如何能够得到n个A,其中能用的操作只有复制和粘贴,并且粘贴只能粘贴最近一次copy的内容。

动态规划:
首先,我们可以先尝试一些较小的数,体会一下其中的规律,我尝试了一下11以内,然后首先发现所有的素数的操作次数都是自身的n,然后比如8,我们只需要在有4个A的时候,复制一下再粘贴,那么就能得到8个A,为了方便我们的描述,我们设dp[i]表示得到i个A所需要的操作次数,那么 d p [ 8 ] = d p [ 4 ] + 2 dp[8] = dp[4] + 2 dp[8]=dp[4]+2,8是偶数,我们再看9,我们在得到3个A的时候,复制一次,再粘贴两次就得到了9个A,即 d p [ 9 ] = d p [ 3 ] + 3 dp[9] = dp[3] + 3 dp[9]=dp[3]+3,从这里,我们其实就可以窥出一些端倪了,首先得到 i 个A和得到j(j < i)个A有关,也就是说具有最优子结构,因此使用动态规划。但是j的选取我们并不知道,但是必须满足能整除i,即 i % j = 0。在这个的前提下,取选择最小的一个,因此算法如下:

dp[i]表示得到i个A需要的最小的操作次数,状态转移方程:
f [ i ] = min ⁡ j ∣ i ( f [ j ] + i j ) f[i] = \min\limits_{j|i} ( f[j] + \frac{i}{j} ) f[i]=j∣imin​(f[j]+ji​)

代码:

class Solution {
public:
    int minSteps(int n) {
        vector<int> dp(n + 1, INT_MAX);
        dp[1] = 0;

        for (int i = 2; i <= n; i ++)
            for (int j = 1; j < i; j ++)
                if ( i % j == 0)
                    dp[i] = min(dp[i], dp[j] + i/j);

        return dp[n];
    }
};




数学:
从第一个方法的转移方程中,我们得到n个A,实际上我们是把j个A重复复制了i/j遍,也就是 n = j * (n / j),虽然这么写相当于废话,但仔细看转移方程: d p [ n ] = d p [ j ] + n / j dp[n] = dp[j] + n/j dp[n]=dp[j]+n/j,因此实际上我们把n进行了质因数分解,因为递归求解j也是这么做的,因此我们来换个思路,刚刚从n往回看,我们从头开始看:

如果我们将 1 次 Copy All + x 次 Paste 看做一次“动作”的话。
那么一次“动作”所产生的效果就是将原来的字符串变为原来的 x + 1 x + 1 x+1倍。
最终的得到n个A的最小操作次数方案可以等价以下操作流程:

  1. 起始对长度为 1 的记事本字符进行 1 次 C o p y A l l + k 1 − 1 Copy All + k_1 - 1 CopyAll+k1​−1次 Paste 操作(消耗次数为 k 1 k_1 k1​,得到长度为 k 1 k_1 k1​的记事本长度);
  2. 对长度为为 k 1 k_1 k1​ 的记事本字符进行 1 次 C o p y A l l + k 2 − 1 Copy All + k_2 - 1 CopyAll+k2​−1 次 Paste 操作(消耗次数为 k 1 + k 2 k_1 + k_2 k1​+k2​ ,得到长度为 k 1 ∗ k 2 k_1 * k_2 k1​∗k2​的记事本长度)
    … …

最终经过 k 次“动作”之后,得到长度为 n 个A,即有:
n = k 1 ∗ k 2 ∗ k 3 ∗ . . . ∗ k x n = k_1 *k_2 *k_3 *... * k_x n=k1​∗k2​∗k3​∗...∗kx​
因此问题转化为,
K = ∑ k i K = \sum k_i K=∑ki​
求 K K K的最小值。
对于 k i k_i ki​而言 ,如果是一个合数,那么 k i = a ∗ b k_i = a * b ki​=a∗b,很容易证明
a ∗ b > a + b ( a > 1 , b > 1 ) a * b > a + b \quad(a > 1, b > 1) a∗b>a+b(a>1,b>1)
因此 K K K 要取得最小,只需要对 k i k_i ki​ 不断分解,直至不能分解,也就是素数了,这也就是为什么我们一开始尝试看出来的质数的操作次数都是自身n。
因此问题转化为对n进行质因数分解,然后将所有的质因数求和就行了。

代码:

class Solution {
public:
    int minSteps(int n) {
        int ans = 0;
        for (int i = 2; i * i <= n; i ++)
            while (n % i == 0)
            {
                ans += i;
                n /= i;
            }

        if (n != 1) ans += n;

        return ans;
    }
};

标签:int,键盘,次数,k1,粘贴,650,得到,一题,dp
来源: https://blog.csdn.net/qq_41862619/article/details/120381316

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有