观李永乐老师《双蛋问题》解题后感

题目开始前,随便说几句。

  • 随便说几句,就是随随便便说的,看不懂没关系。随便说,可能会表达得不好,当作阅读前的热身

李永乐老师双蛋问题,大概就是讲,给你两个钛合金鸡蛋,在100层楼中去测试鸡蛋的耐摔度,就是摔碎鸡蛋的临界点。问你最少要试扔多少次(不是多少个,是扔多少次),这两个鸡蛋是你的科研经费能买到的唯一物质。

之后, 李永乐老师,把问题难度提高,给你K个鸡蛋,在N层测耐摔度,最少要扔多少次。

在看本题之前,最好看看李永乐老师的解题思想。

本题用到的算法是动态规划 + 二分查找

其实这道题目,只懂得计算机的动态规划和二分查找是不够的解答的。

因为,看完视频还不满足,所以就专门跑去 leetcode找一下同款题目来做。

力扣原题如下:

  1. 鸡蛋掉落
  • 你将获得 K 个鸡蛋,并可以使用一栋从 1 到 N 共有 N 层楼的建筑。

  • 每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。

  • 你知道存在楼层 F ,满足 0 <= F <= N 任何从高于 F 的楼层落下的鸡蛋都会碎,从 F 楼层或比它低的楼层落下的鸡蛋都不会破。

  • 每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层 X 扔下(满足 1 <= X <= N)。

  • 你的目标是确切地知道 F 的值是多少。

  • 无论 F 的初始值如何,你确定 F 的值的最小移动次数是多少?


  • 示例 1:

    输入:K = 1, N = 2
    输出:2

  • 解释: 鸡蛋从 1 楼掉落。如果它碎了,我们肯定知道 F = 0 。 否则,鸡蛋从 2
    楼掉落。如果它碎了,我们肯定知道 F = 1 。 如果它没碎,那么我们肯定知道 F = 2 。 因此,在最坏的情况下我们需要移动 2
    次以确定 F 是多少。


  • 示例 2:

输入:K = 2, N = 6
输出:3


  • 示例 3:

输入:K = 3, N = 14 输出:4

  • 提示:

1 <= K <= 100
1 <= N <= 10000

力扣原题
链接如下:https://leetcode-cn.com/problems/super-egg-drop/

随后经过细品,才知道这道题目单单靠算法思维:动态规划 + 二分查找仍然无法解答(仅仅靠动态规划,可以解答,但是算法时间复杂度为O(KNN) ,太高了).

所以为了优化动态规划的选择策略,你采用二分查找,从选项中快速的找到最优解。

但是你采用二分查找得先证明离散数组具备单调性,要么单调性递增(/上坡形),要么单调递减(\下坡形),要么分成2段后具备单调性(V字形)

你要证明单调性就得运用数学证明,证明鸡蛋个数一定的情况下,楼层数越高,最少需要扔蛋次数就越大。

本题框架:

利用递归代代替迭代法实效动态规划解空间dp的生成。
我们大部分都是利用for循环(forfor,或者forforfor)和动态转移方程,自底向上的运算,生产解空间。

本题利用递归法中回溯的过程,实现自底向上,生产解空间,本质上并没什么高明之处。对于习惯看for循环的人来说,可读性还变差了。(其实按照这个思维,动态规划有点像,带memo的递归回溯算法)

其次就是关于复杂度的运算,对很多人习惯通过for循环的层数来估算时间复杂度(正确的做法应该是看状态的笛卡尔积大小。比如本题是N,K两个状态,那么他们两个维度的笛卡尔积大小为NK),也变得不那么明朗。(这套框架,时间复杂度依然是O(NK),不是这套算法。因为我们的策略采用了二分查找,所以复杂度是lgn,本题的复杂度是O(NKLgn)).

而本题状态转移方程中涉及对多个选项择优(从竞争者中择优,竞争者由候选者dp(n,k)通过业务模型生成)的策略算法在递归函数中实现。

注意对递归方式起步进行边界判断。

本题解法比较精彩的操作:

  • 利用哈希表来代替二维数组,提高了dp表下标可读性。
  • 利用带memo备忘录的递归回溯算法实现动态规划。
  • 利用二分查找策略在众多选项中找到最优解。
  • 利用函数单调性,证明可以采用二分查找策略,并设计出了二分查找分界点的判定函数(用来判定怎么缩小搜索范围)。
  • 二分查找几个要素处理的很漂亮:
    • 搜索范围的定义
    • 分界点的定义
    • 缩小搜索范围用到的判定函数(判定函数的参数就是分界点了)。
    • 终止搜索的区间定义。
    • 因为我们二分查找的变量是区间,所以终止条件也是区间的坐标值。
  • 本题完美考虑到了离散型区间的元素个数的奇偶性问题。
  • 递归的边界判断条件 if (!memo.containsKey(N * 100 + K))写在前头也很漂亮
  • 充分的考虑到了动态规划的 Base Case,即鸡蛋数为0和楼层数为1的情况。

class Solution {public int superEggDrop(int K, int N) {return dp(K, N);}/* 用哈希表模拟二维数组,减少下标堆运算的干扰。提高代码的可读性。哈希表也具备下标访问的能力。而哈希函数可以解决存储的问题。所以多维数组,如果知道下标的上下限可以采用哈希表加坐标编码的方式提高可读性。如本题,鸡蛋最多100个,楼层最多10000个。我们采用编码为NK,比如8889层楼,89个鸡蛋。那么key为888989(或者同理,898889,也可以)我们可以用字符串运算,“8889” + “89”其实没必要,因为最大数是10000100.这个值在int范围内,所以我们采用int即可,比如,N = 8889,K = 89我们只需要通过,位运算的思想,N*100 + K,即可得到888989,其中100就是偏移。*/   Map<Integer, Integer> memo = new HashMap();public int dp(int K, int N) {// 递归函数的边界判断if (!memo.containsKey(N * 100 + K)) {// 截至目前解空间的最优解int ans;// 初始化 base caseif (N == 0)ans = 0;else if (K == 1)ans = N;else {// 二分查找begin/**在选项中i是变量,选项值是结果,而且选项i的最小值位于区间中部,满足二分查找的应用条件。所以我们可以采用二分查找使其复杂度从O(n)变差O(lgn)二分查找,就是定义搜索域的访问然后定义一个分界点,对分界点做布尔函数运算,得出boolean结果,利用boolean结果缩小搜索范围。直到搜索范围缩小为约定大小。本题,范围 1 ~ N,表示楼层范围。lo为搜索范围起点,hi为搜索范围的终点。初始化为[1,N]定义一个分界点,分界点就是:搜索范围是离散型区间,所以我们可以取区间中间值,如果是偶数个,中间值有两个,取第1个。如果中间值只有一个,那就直接取。所以我们的分界点方程为: middle = (ol + hi)/2分界点的布尔函数为:算出选项值,由于选项是离散的。如果当前选项比(middle + 1)的选项大,且比(middle-1)选项小,那么就说明当前选项处于递减趋势,不是最小值(类似U形抛物线的左半段)。所以最小值在middle的右侧,因此调整左侧起点坐标lo为middle,缩小搜索范围,继续迭代搜索。如果当前选项比(middle + 1)的选项小,且比(middle-1)选项大,那么就说明当前选项处于递增趋势,不是最小值。所以最小值在middle的左侧,因此调整右侧终点坐标hi的为middle,缩小搜索范围,继续迭代搜索。约定搜索终止的搜索区间,二分查找的变量是区间,所以我们要约定终止区间(不能笼统的说是终止条件)。约定终止区间为 如果当前区间大小是奇数,则ol == hi ,如果当前区间大小是偶数,则 ol+1 == hi(因为我们定义了偶数个的起点ol是两个中间值的第一个,所以终止条件才会是ol + 1 == hi, 这就叫百因必有果,很佛系)。*/int lo = 1, hi = N;while (lo + 1 < hi) {int x = (lo + hi) / 2;/*这里采用分段函数的思想来判断趋势。                    不过怎么都是在判断趋势,无差。因为我们从状态转移方程中生成选项的算法中找到分段函数的规律。动态转移方程中可以知道,一个鸡蛋从第i层落下,会有碎和不碎两种情况。 i越高,t1的楼层数越高,t2的楼层数越少。碎的情况t1,从公式来看,K,N不变的情况下,x-1是递增函数,所以从i=1开始时,t1肯定比较小。而大概率不会被作为选项的最终值,因为选项的最终值会从t1和t2选择最大的值。而不碎的情况则相反,t2是递减函数从i=1开始时,t2的值比较大,所以大概率会被选中。我们我们可以从t1和t2的大小来判断,当前的趋势,将趋势作为分界点的布尔函数。思路是对的,不过还有个问题,我们的思路是基于函数递增递减趋势来实现的,我们知道递增递减趋势需要考虑单调性,而不具备单调性,那么二分查找的分界点的布尔函数将会不稳定,从而出现误判情况,最后搜索范围的选择会出现错误。所以我们需要证明一个命题:鸡蛋个数一定的情况下,楼层数越高,确定F的最少次数就会越高。我们如果能从动态规划方程中证明这一点,那么整个思路就通顺的。*/int t1 = dp(K-1, x-1);int t2 = dp(K, N-x);if (t1 < t2)lo = x;else if (t1 > t2)hi = x;elselo = hi = x;}// 二分查找end    ans = 1 + Math.min(Math.max(dp(K-1, lo-1), dp(K, N-lo)),Math.max(dp(K-1, hi-1), dp(K, N-hi)));}memo.put(N * 100 + K, ans);}return memo.get(N * 100 + K);}
}

总结

  • 总结都写在前头了,所以没什么总结的。

  • 说白点,这道题就是一个2维状态的动态规划题,只是择优策略比较复杂,用到了二分查找。

  • 二分查找本来就是需要考虑单调性问题,才能用的数学算法。

  • 学会这题等于掌握了动态规划和二分查找。

  • 以及怎么使用哈希表代替多维数组的方法。

  • 说说动态规划蛋疼的缺点,就是一旦变动的状态有多个的话,并且还要求所有状态都会被用到一次,就会出现时间复杂度幂函数级别的增长了。比如本题,有2个状态,N,K,所以时间复杂度是O(NK)起步,如果有3个状态就是o(n^3)次方了。所以有时候为了减少时间复杂度,得考虑怎么减少dp解空间的计算量。最理想的情况就是假如有3个状态,N1,N2,N3 找到一个算法时间复杂度为:O(N1 * logN2 * logN3)。这种题目通常都要求用到数学方法。

观李永乐老师《双蛋问题》解题后感相关推荐

  1. 阿里达摩院数学竞赛新一轮考题曝光,李永乐老师曾给出第一题详细解答

    乾明 发自 凹非寺  量子位 报道 | 公众号 QbitAI 三万多人,冥思苦想两天两夜没交卷! 今天,阿里达摩院全球数学竞赛第二轮预选赛结束,战况依旧惨烈: 全球共有5万多名选手报名,最终1.6万多 ...

  2. [dp]双蛋问题李永乐老师视频

    2022.10.1更新,此题目在leetcode.cn上有原题,并且有大量详细的题解,见 887. 鸡蛋掉落 一.背景 今天看李永乐老师的科普视频,里面提到的双蛋问题很有意思.思考了下发现是动态规划问 ...

  3. 观李永乐《皇帝的新衣》后感以及红蓝眼悖论解题思路

    观李永乐<皇帝的新衣>后感以及红蓝眼悖论解题思路 前言 写这篇博客不是主要的目的: 不是为了提供这题目的答案. 不是为了讲"共有知识"和"公共知识" ...

  4. 李永乐讲卷积神经网络,李永乐老师讲人工智能

    清华大学李永乐老师坐拥千万粉丝,他的课堂有什么魅力? 清华大学李永乐老师拥有上千万的粉丝,这个粉丝拥有量自己觉得很正常,因为每年都有上百万的学子关注这个老师,因为到考研的过程中有一个很大的难题就是数学 ...

  5. 李永乐老师讲一个量子计算机,别再只知道罗翔了!网上最受欢迎的14位老师,个个让人“开天眼”!...

    除了推荐「学什么」,这次,我还要推荐「跟谁学」. 第一反应,是跟着大学老师学习! 虽然我是北大清华得不到的人,但是听听高校老师讲课,还是 ok 的. 这里借用一位网友的话: 经过在网络上长时间的学习, ...

  6. 李永乐讲解计算机科学与技术,【视频】李永乐老师讲解“哥德巴赫猜想”【民科吧】_百度贴吧...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 李老师我有一个证明请你审阅:哥德巴赫猜想的证明 摘要:本文证明了任意≥6的偶数都必可表为两个素数之和.证明中是令任意正整数2M为元素的个数,由2M的两两不 ...

  7. 李永乐老师卷积神经网络

    https://www.youtube.com/watch?v=AFlIM0jSI9I 卷积过程 卷积核表示图像特征,比如一个右下的线条. 卷积核在图像上移动,做运算,就会得图像的特征图(粉色的.有右 ...

  8. 李永乐老师讲解MindSpore

    参考:https://www.zhihu.com/zvideo/1452361569703718912 1.人工智能框架:不是从零开始编写,有些已经编好了放在那里了,做菜的厨师不会从种子开始做菜,建筑 ...

  9. 李永乐老师讲辛普森悖论

    有个小朋友跟我说:他特别喜欢看篮球比赛,最喜欢的球星是湖人队的勒布朗·詹姆斯.他曾经把詹姆斯和历史上的著名球员马龙做过比较,结果发现了一个神奇的现象:在整个生涯中,无论是二分球的命中率还是三分球的命中 ...

最新文章

  1. 第五章ThinkingInJava
  2. LOL快要凉?腾讯电竞应如何破除游戏生命周期诅咒
  3. 一文搞定JS中的DOM基础与进阶
  4. html和css制作动漫岛,CSS动画
  5. 26_多线程_第26天(Thread、线程创建、线程池)_讲义
  6. linux一行多个命令行,如何在一行中运行多个Linux命令
  7. Module build failed: Error: Node Sass version 5.0.0 is incompatible with ^4.0.0.
  8. python静态代码检查_想要开发一个供 Python 使用的静态类型检查项目
  9. 模拟线性调制系统的仿真
  10. 核方法(kernel method)的主要思想
  11. 博文视点大讲堂第44期——招聘真相全揭秘 圆满结束
  12. VB2010(17)_消息对话框MessageBox
  13. 卸载JLink驱动弹出“could not open INSTALL.LOG file”的解决方法
  14. 2022年湖北安全员ABC证书查询是在哪里查真假呢?
  15. 台式计算机亮度设置,怎么调台式电脑亮度_怎么调台式电脑的亮度
  16. 离散数学中 集合、关系、群 的证明方法(英文证明附例题)
  17. 【附源码】Python计算机毕业设计人事管理系统
  18. 4rx4 服务器内存2rx4_【P00930-B21 P06190-001 64GB 2Rx4 PC4-2933Y-R 服务器内存】价格_厂家 - 中国供应商...
  19. 树莓派+USB摄像头进行网络监控—MJPG-Streamer
  20. sipML5实现语音信息服务

热门文章

  1. 服务器10的系统杀毒怎么关,Win10自带杀毒软件怎么关闭?彻底关闭Windows Defender方法...
  2. vue进阶实战 vue进阶课程 vue进阶
  3. 人类一败涂地做图教程_人类一败涂地地图制作教程 创意工坊自制地图方法
  4. 国医中药,人参神秘而又独特的地位
  5. com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Expression #1 of SELECT list is not in GR
  6. 考研—计算机网络—应用层
  7. C#图片截取压缩(百分比压缩/大小压缩)实现代码
  8. 西安交通大学护理学计算机考试,西安交通大学护理专业怎么样
  9. 8266 lua贝壳物联智能开关,更新修正tmr.alarm问题
  10. 树莓派教程 - 1.5 树莓派GPIO库wiringPi 使用硬件串口ttyAMA0与ttyS0