LeetCode:字符串延长到指定长度需要最少的操作次数

Initially on a notepad only one character 'A' is presest.You can perform two operations 
on this notepad for each step:
(1)Copy All:You can copy all the characters present on the notepad(partial copy is not allowed).
(2)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'.

题目大意:
给定一个字母A,你可以每次选择复制全部字符或者粘贴上一次复制的字符,求最少需要多少次操作可以
把字符串延展到指定长度.

解题思路:
方法1:
素数分解.所有的操作都是以copy为首,paste结束.这样可以分成多组,[cpp][cpppp][cp]....,
假设每组的长度分别为:x1,x2,x3...xn.
(1)第一组操作后,字符串总共有x1个A;
(2)第二组操作后,字符串总共有x1*x2个A;
(3)第n组操作后,字符串总共有x1*x2....*xn个A;
若xi是合数,则存在xi=p*q,那么可以分成两组,第一组包含1个copy和p-1个paste,第二组包含1个copy
和q-1个paste.

证明这种分割方式下需要的次数达到最少.p+q<=p*q,则1<=(p-1)(q-1),当p且q>=2时条件都成立.
本题就是N的素数分解过程.

方法2:
动态规划.需要乘除法来计算位置,因为粘贴操作是倍数增加的.设定数组dp[i],其中位置i表示延展到长度i的
最少操作次数.对于每个位置j,如果j可以被i整数,那么长度i就可以由长度j操作得到,其操作次数等价于把一个
长度为1的A延展到长度为i/j.因此可以得到递推公式:
dp[i]=dp[j]+dp[i/j]
#include <iostream>
#include <vector>
#include <cmath>

using namespace std;
class Solution{
public:
    int minSteps1(int n){
        int ans=0,d=2;/*2是最小的素数因子*/
        while(n>1){
            while(n%d==0){
                ans+=d;/*整除则证明当前n仍为其素数因子*/
                n/=d;
            }
            /*若不是则继续进行试探*/
            d++;
        }
        return ans;
    }
    int minSteps2(int n){
        int ans=0,d=0;
        while(n!=1){
            d=findMaxDivisor(n);
            ans+=n/d;
            n=d;
        }
        return ans;
    }

    int minSteps(int n){
        vector<int> dp(n+1);
        int h=sqrt(n);
        for(int i=2;i<=n;i++){
            dp[i]=i;
            for(int j=2;j<=h;j++){
                if(i%j==0){
                    dp[i]=dp[j]+dp[i/j];
                    break;
                }
            }
        }
        return dp[n];
    }
private:
    /*找最大因数,范围:1<=d<=d/2*/
    int findMaxDivisor(int n){
        int max=n/2;
        for(int i=max;i>=2;i--){
            if(n%i==0)
               return i;
        }
        return 1;
    }
};

int main(int argc,char* argv[]){
    cout<<Solution().minSteps(6)<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

路上的追梦人

您的鼓励就是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值