zoukankan      html  css  js  c++  java
  • LeetCode——四键键盘

    Q:假设你有一个特殊的键盘包含下面的按键:
    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 位有符号整数范围。

    A:
    状态转移:

    写出代码:

        public int maxA(int N) {
            if (N <=1)
                return N;
            int a_num = 0;
            int copy = 0;
            return dp(N, a_num, copy);
        }
    
        private int dp(int n, int a_num, int copy) {
            if (n <= 0)//注意这里一定是<=0
                return a_num;
            return max(dp(n - 1, a_num + 1, copy), dp(n - 1, a_num + copy, copy), dp(n - 2, a_num, a_num));
        }
    
        private int max(int a, int b, int c) {
            return Math.max(Math.max(a, b), c);
        }
    

    但这样会超时。我们用memo记录一下:

        Map<int[], Integer> memo = new HashMap<>();
    
        public int maxA(int N) {
            if (N <= 1)
                return N;
            int a_num = 0;
            int copy = 0;
            return dp(N, a_num, copy);
        }
    
        private int dp(int n, int a_num, int copy) {
            if (n <= 0)
                return a_num;
            int[] array = new int[]{n, a_num, copy};
            if (memo.containsKey(array))
                return map.get(array);
            int max = max(dp(n - 1, a_num + 1, copy), dp(n - 1, a_num + copy, copy), dp(n - 2, a_num, a_num));
            memo.put(array, max);
            return max;
        }
    
        private int max(int a, int b, int c) {
            return Math.max(Math.max(a, b), c);
        }
    

    还是超时了。

    考虑第二种写法:
    这个算法基于这样⼀个事实,最优按键序列⼀定只有两种情况:要么⼀直按 A :A,A,...A(当 N ⽐较⼩时)。要么是这么⼀个形式:A,A,...C-A,C-C,C-V,C-V,...C-V(当 N ⽐较⼤时)。因为字符数量少(N ⽐较⼩)时, C-A C-C C-V 这⼀套操作的代价相对⽐较⾼,可能不如⼀个个按 A ;⽽当 N ⽐较⼤时,后期 C-V 的收获肯定很⼤。这种情况下整个操作序列⼤致是:开头连按⼏个 A ,然后 C-A C-C组合再接若⼲ C-V ,然后再 C-A C-C 接着若⼲ C-V ,循环下去。换句话说,最后⼀次按键要么是 A 要么是 C-V 。
    由于最优的操作序列⼀定是 C-A C-C 接着若⼲ C-V ,所以我们⽤⼀个变量 j 作为若⼲ C-V 的起点。那么 j 之前的 2 个操作就应该是 C-A C-C 了:

        public int maxA(int N) {
            if (N <= 1)
                return N;
            int[] dp = new int[N + 1];
            dp[0] = 0;
            for (int i = 1; i <= N; i++) {
                dp[i] = dp[i - 1] + 1;//按 A 键
                //全选 & 复制 dp[j-2],连续粘贴 i - j 次
                for (int j = 2; j < i; j++) {
                    //屏幕上共 dp[j - 2] * (i - j + 1) 个 A
                    dp[i] = Math.max(dp[i], dp[j - 2] * (i - j + 1));
                }
            }
            return dp[N];
        }
    
  • 相关阅读:
    Spring Boot面试题(转至)
    深入理解Java输入输出流
    java基础 第十六章(连接数据库)
    java基础 第十五章(数据库)
    java基础 第十四章(Servlet声明周期、Servlet向jsp中提供数据、Servlet跳转jsp、jsp中书写java代码)
    java基础 第十三章(HashMap、Servlet介绍)
    java基础 第十二章(异常处理、工具类、集合)
    java基础 第十一章(多态、抽象类、接口、包装类、String)
    java基础 第十章(this,继承,重写和重载的区别)
    java基础 第九章(设计模式 单例模式)
  • 原文地址:https://www.cnblogs.com/xym4869/p/12591717.html
Copyright © 2011-2022 走看看