zoukankan      html  css  js  c++  java
  • Leetcode [650] 只有两个键的键盘 & Leetcode [651] 四键键盘 动态规划

    /*
     * @lc app=leetcode.cn id=650 lang=cpp
     *
     * [650] 只有两个键的键盘
     *
     * https://leetcode-cn.com/problems/2-keys-keyboard/description/
     *
     * algorithms
     * Medium (52.48%)
     * Likes:    279
     * Dislikes: 0
     * Total Accepted:    21.6K
     * Total Submissions: 41K
     * Testcase Example:  '3'
     *
     * 最初在一个记事本上只有一个字符 'A'。你每次可以对这个记事本进行两种操作:
     * 
     * 
     * Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的)。
     * Paste (粘贴) : 你可以粘贴你上一次复制的字符。
     * 
     * 
     * 给定一个数字 n 。你需要使用最少的操作次数,在记事本中打印出恰好 n 个 'A'。输出能够打印出 n 个 'A' 的最少操作次数。
     * 
     * 示例 1:
     * 
     * 
     * 输入: 3
     * 输出: 3
     * 解释:
     * 最初, 我们只有一个字符 'A'。
     * 第 1 步, 我们使用 Copy All 操作。
     * 第 2 步, 我们使用 Paste 操作来获得 'AA'。
     * 第 3 步, 我们使用 Paste 操作来获得 'AAA'。
     * 
     * 
     * 说明:
     * 
     * 
     * n 的取值范围是 [1, 1000] 。
     * 
     * 
     */

    思路:

    当n = 1时,已经有一个A了,我们不需要其他操作,返回0

    当n = 2时,我们需要复制一次,粘贴一次,返回2

    当n = 3时,我们需要复制一次,粘贴两次,返回3

    当n = 4时,这就有两种做法,一种是我们需要复制一次,粘贴三次,共4步,另一种是先复制一次,粘贴一次,得到AA,然后再复制一次,粘贴一次,得到AAAA,两种方法都是返回4

    当n = 5时,我们需要复制一次,粘贴四次,返回5

    当n = 6时,我们需要复制一次,粘贴两次,得到AAA,再复制一次,粘贴一次,得到AAAAAA,共5步,返回5

    可以看出对于n,至多需要n步,即cppppp....,而如果可以分解成相同的几份,则可以减少次数,比如n=6时,目标是AAAAAA,可以分解为两个AAA或者三个AA,所以递推公式为:

    dp[i] = min(dp[i], dp[j] + i / j);
    i为1~n,j为1~i,i为外循环,j为内循环

    class Solution {
    public:
        int minSteps(int n) {
            vector<int> dp(n+1,n);
            dp[0]=0;
            dp[1]=0;
            for(int i=2;i<=n;++i){
                dp[i]=i;
                for(int j=2;j<=i/2;++j){
                    if(i%j==0){
                        dp[i]=min(dp[i],dp[j]+i/j);
                    }
                }
            }
            return dp[n];
        }
    };

    【四键键盘】

    假设你有一个特殊的键盘包含下面的按键:

    Key 1: (A):在屏幕上打印一个 'A'。

    Key 2: (Ctrl-A):选中整个屏幕。

    Key 3: (Ctrl-C):复制选中区域到缓冲区。

    Key 4: (Ctrl-V):将缓冲区内容输出到上次输入的结束位置,并显示在屏幕上。

    现在,你只可以按键 N 次(使用上述四种按键),请问屏幕上最多可以显示几个 'A'呢?

    样例 1:

    输入: N = 3
    输出: 3
    解释:
    我们最多可以在屏幕上显示三个'A'通过如下顺序按键:
    A, A, A
     

    样例 2:

    输入: N = 7
    输出: 9
    解释:
    我们最多可以在屏幕上显示九个'A'通过如下顺序按键:
    A, A, A, Ctrl A, Ctrl C, Ctrl V, Ctrl V
     

    注释:

    1 <= N <= 50
    结果不会超过 32 位有符号整数范围。

    思路:labuladong

    这个算法基于这样一个事实,最优按键序列一定只有两种情况

    要么一直按A:A,A,…A(当 N 比较小时)。

    要么是这么一个形式:A,A,…C-A,C-C,C-V,C-V,…C-V(当 N 比较大时)

    最后一次按键要么是A要么是C-V。明确了这一点,可以通过这两种情况来设计算法

    int[] dp = new int[N + 1];
    // 定义:dp[i] 表示 i 次操作后最多能显示多少个 A
    for (int i = 0; i <= N; i++) 
        dp[i] = max(
                这次按 A 键,
                这次按 C-V
            )

    对于「按A键」这种情况,就是状态i - 1的屏幕上新增了一个 A 而已,很容易得到结果:

    // 按 A 键,就比上次多一个 A 而已
    dp[i] = dp[i - 1] + 1;

    刚才说了,最优的操作序列一定是C-A C-C接着若干C-V,所以我们用一个变量j作为若干C-V的起点。那么j之前的 2 个操作就应该是C-A C-C

    class Solution {
    public:
        int maxA(int n) {
            vector<int> dp(n+1,0);
            dp[0]=0;
            for(int i=1;i<=n;++i){
                dp[i]=dp[i-1]+1; // A
                for(int j=2;j<i;++j){
                    dp[i]=max(dp[i],dp[j-2]*(i-j+1));
                }
            }
            return dp[n];
        }
    };
    联系方式:emhhbmdfbGlhbmcxOTkxQDEyNi5jb20=
  • 相关阅读:
    IntelliJ IDEA下自动生成Hibernate映射文件以及实体类
    java 调用本地应用程序 Java打开(.word,.txt,.pdf)文件
    使用GooSeeker爬取数据
    pycharm、idea 2018软件安装教程
    GUI JFrame窗体介绍:
    KindEditor的参考文献
    Python自动化开发学习20-Django的form组件
    Navicat安装教程、建表教程
    import与from...import...的区别
    动态添加,删除和保存
  • 原文地址:https://www.cnblogs.com/zl1991/p/14742514.html
Copyright © 2011-2022 走看看