• lintcode 584 · 丢鸡蛋II 【中等 vip 动态规划】


    题目

    https://www.lintcode.com/problem/584

    有一个n层的建筑。如果一个鸡蛋从第k层及以上落下,它会碎掉。如果从低于这一层的任意层落下,都不会碎。
    有m个鸡蛋,用最坏的情况下实验次数最少的方法去找到k, 返回最坏情况下所需的实验次数。
    
    
    样例
    例1:
    
    输入: m = 2, n = 100 
    输出: 142:
    
    输入: m = 2, n = 36 
    输出: 8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    思路

    	有两种方法,本质一样的,第一种递归,会超时但能出来结果,第二种动态规划。
        第一种递归当楼层是10还好,如果是100,程序会运行很久,几分钟也没出来结果,
        还在递归,提交了也不能过,但是对第二种解法有启发性。
    
        递归方程:
        DropEggs(m,n) = min(1+max(DropEggs(m-1,x-1),DropEggs(m, n-x)),x=1,...n)
        递归出口:
        当m为0或n为0返回0,
        当m为1返回n,
        当n为1返回1。
        解释:
        假设从x楼扔鸡蛋,如果碎了,最低的碎鸡蛋楼层低于x,那么此时剩下m-1个鸡蛋,
        只需要探索x-1层楼,如果没碎,最低的碎鸡蛋楼层在x层的上面,那么此时剩下m个鸡蛋,
        只需探索x层以上的共n-x层,
        由于两种都有可能,题目问的是最坏情况,那么取两种情况下需要扔鸡蛋次数多的情况,
        也就是 max(DropEggs(m-1,x-1),DropEggs(m, n-x))
        那么,如果从x层开始扔,一共需要扔1+max(DropEggs(m-1,x-1),DropEggs(m, n-x))次,
        1代表扔第x层的一次。我们需要知道最优的x,也就是题目问的需要最小的次数,
        那么就需要把x的所有可能都试一试,最终得到答案,x的所有可能是1,…,n。
        当没有鸡蛋或没楼层,次数为0,
        当只有一个鸡蛋只能从一楼开始往上试,最坏是试完所有楼层,
        当只有一层时,只需试一次。
        时间复杂度:
        指数级别
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    注意:动态规划版本本身是由递归修改而来

    参考答案

    本答案的递归版本是参数较大的话,不通过,但是答案没有错,可以用于本地测试;
    如果读者使用我的代码,务必注意方法加静态标识符。或者把我的答案静态方法都写为非静态方法,反正要统一

    public class Solution {
        /**
         * @param m: the number of eggs
         * @param n: the number of floors
         * @return: the number of drops in the worst case
         */
        public static int dropEggs2(int m, int n) {
              //return (int)f1(m,n);  //递归,超时了
            return dp(m,n);  //动态规划
        }
    
        public static int dp(int m,int n){
            int[][] dp = new int[m+1][n+1];
            //填充第一列
            for (int i = 1; i <=m ; i++) {
                dp[i][0]=0;
                dp[i][1]=1;
            }
    
            for (int j = 1; j <=n ; j++) { //填充第二行
                dp[1][j] =j;
            }
    
            for (int i = 2; i <=m ; i++) {
                for (int j = 2; j <=n ; j++) {
                    dp[i][j] =Integer.MAX_VALUE;
                    for (int k = 1; k <j ; k++) {
                        int tmp = 1+Math.max(dp[i-1][k-1],dp[i][j-k]);
                        dp[i][j]=Math.min(dp[i][j],tmp);
                    }
                }
            }
    
            return dp[m][n];
        }
    
        //递归
        public static long f1(int m,int n){
            /*
            有两种方法,本质一样的,第一种递归,会超时但能出来结果,第二种动态规划。
            第一种递归当楼层是10还好,如果是100,程序会运行很久,几分钟也没出来结果,
            还在递归,提交了也不能过,但是对第二种解法有启发性。
    
            递归方程:
            DropEggs(m,n) = min(1+max(DropEggs(m-1,x-1),DropEggs(m, n-x)),x=1,...n)
            递归出口:
            当m为0或n为0返回0,
            当m为1返回n,
            当n为1返回1。
            解释:
            假设从x楼扔鸡蛋,如果碎了,最低的碎鸡蛋楼层低于x,那么此时剩下m-1个鸡蛋,
            只需要探索x-1层楼,如果没碎,最低的碎鸡蛋楼层在x层的上面,那么此时剩下m个鸡蛋,
            只需探索x层以上的共n-x层,
            由于两种都有可能,题目问的是最坏情况,那么取两种情况下需要扔鸡蛋次数多的情况,
            也就是 max(DropEggs(m-1,x-1),DropEggs(m, n-x))
            那么,如果从x层开始扔,一共需要扔1+max(DropEggs(m-1,x-1),DropEggs(m, n-x))次,
            1代表扔第x层的一次。我们需要知道最优的x,也就是题目问的需要最小的次数,
            那么就需要把x的所有可能都试一试,最终得到答案,x的所有可能是1,…,n。
            当没有鸡蛋或没楼层,次数为0,
            当只有一个鸡蛋只能从一楼开始往上试,最坏是试完所有楼层,
            当只有一层时,只需试一次。
            时间复杂度:
            指数级别
             */
            if(m ==0 || n==0) return 0;
            if(m ==1) return n;
            if(n==1) return 1;
            long ans = Long.MAX_VALUE;
            for (int i = 2; i <n+1 ; i++) {
                long tmp = 1+Math.max(dropEggs2(m-1,i-1),dropEggs2(m,n-i));
                if(ans > tmp)
                    ans = tmp;
            }
    
            return ans;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    本地测试的代码

    public class LC584 {
    
        public static int dropEggs2(int m, int n) {
            //return (int)f1(m,n);  //递归,超时了
            return dp(m,n);  //动态规划
        }
    
        public static int dp(int m,int n){
            int[][] dp = new int[m+1][n+1];
            //填充第一列
            for (int i = 1; i <=m ; i++) {
                dp[i][0]=0;
                dp[i][1]=1;
            }
    
            for (int j = 1; j <=n ; j++) { //填充第二行
                dp[1][j] =j;
            }
    
            for (int i = 2; i <=m ; i++) {
                for (int j = 2; j <=n ; j++) {
                    dp[i][j] =Integer.MAX_VALUE;
                    for (int k = 1; k <j ; k++) {
                        int tmp = 1+Math.max(dp[i-1][k-1],dp[i][j-k]);
                        dp[i][j]=Math.min(dp[i][j],tmp);
                    }
                }
            }
    
            return dp[m][n];
        }
    
        //递归
        public static long f1(int m,int n){
            /*
            有两种方法,本质一样的,第一种递归,会超时但能出来结果,第二种动态规划。
            第一种递归当楼层是10还好,如果是100,程序会运行很久,几分钟也没出来结果,
            还在递归,提交了也不能过,但是对第二种解法有启发性。
    
            递归方程:
            DropEggs(m,n) = min(1+max(DropEggs(m-1,x-1),DropEggs(m, n-x)),x=1,...n)
            递归出口:
            当m为0或n为0返回0,
            当m为1返回n,
            当n为1返回1。
            解释:
            假设从x楼扔鸡蛋,如果碎了,最低的碎鸡蛋楼层低于x,那么此时剩下m-1个鸡蛋,
            只需要探索x-1层楼,如果没碎,最低的碎鸡蛋楼层在x层的上面,那么此时剩下m个鸡蛋,
            只需探索x层以上的共n-x层,
            由于两种都有可能,题目问的是最坏情况,那么取两种情况下需要扔鸡蛋次数多的情况,
            也就是 max(DropEggs(m-1,x-1),DropEggs(m, n-x))
            那么,如果从x层开始扔,一共需要扔1+max(DropEggs(m-1,x-1),DropEggs(m, n-x))次,
            1代表扔第x层的一次。我们需要知道最优的x,也就是题目问的需要最小的次数,
            那么就需要把x的所有可能都试一试,最终得到答案,x的所有可能是1,…,n。
            当没有鸡蛋或没楼层,次数为0,
            当只有一个鸡蛋只能从一楼开始往上试,最坏是试完所有楼层,
            当只有一层时,只需试一次。
            时间复杂度:
            指数级别
             */
            if(m ==0 || n==0) return 0;
            if(m ==1) return n;
            if(n==1) return 1;
            long ans = Long.MAX_VALUE;
            for (int i = 2; i <n+1 ; i++) {
                long tmp = 1+Math.max(dropEggs2(m-1,i-1),dropEggs2(m,n-i));
                if(ans > tmp)
                    ans = tmp;
            }
    
            return ans;
        }
    
    
        public static void main(String[] args) {
            System.out.println(dropEggs2(2,36)); //8
            System.out.println(dropEggs2(2,100)); //14
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    数字转型 | 论指标解析在数据治理中的作用
    logback源码阅读(三) springboot对LoggingSystem日志系统的支持
    如何解决版本不兼容Jar包冲突问题
    首次公开,GitHub点击破百万的分布式高可用算法小册被我扒下来了
    千峰课程网安笔记(1)
    【SnowFlake】雪花算法(Java版本)
    基于ZigBee设计的物联网LED控制系统
    双S曲线轨迹(详细推导)
    MySQL DDL执行方式-Online DDL介绍
    SpringBoot(基础篇 ==> 详解yaml文件的使用
  • 原文地址:https://blog.csdn.net/weixin_37991016/article/details/132866925