leetcode-887-鸡蛋掉落(包含最大值最小化,最小值最大化的二分优化+滚动数组的原理)

news2024/11/26 0:54:52

这里写目录标题

  • 题意
  • 解题
    • KNN复杂度DP解法思想(超时)
    • 上述方法的优化 (最大值最小化二分优化)
      • 完整代码
    • 逆向思维的DP
      • 代码
        • 空间优化(滚动数组)
        • 代码

题意

链接:leetcode-887-鸡蛋掉落
给你 k 枚相同的鸡蛋,并可以使用一栋从第 1 层到第 n 层共有 n 层楼的建筑。

已知存在楼层 f ,满足 0 <= f <= n ,任何从 高于 f 的楼层落下的鸡蛋都会碎,从 f 楼层或比它低的楼层落下的鸡蛋都不会破。

每次操作,你可以取一枚没有碎的鸡蛋并把它从任一楼层 x 扔下(满足 1 <= x <= n)。如果鸡蛋碎了,你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎,则可以在之后的操作中 重复使用 这枚鸡蛋。

请你计算并返回要确定 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

解题

KNN复杂度DP解法思想(超时)

  • 表示: dp[i][j]: 表示i个鸡蛋,j层楼的最少移动次数
  • 初始状态: dp[0][:] = dp[:][0]=0, dp[1][h]=h(h从1层到n层:很好理解,1个鸡蛋h层,只能从1层慢慢往上试错)
  • 状态转移: 考虑dp(i, j):i个鸡蛋j层需要最少移动多少次数,那么i个鸡蛋我们考虑从k层仍(k在1~j层),dp(i, j) ----- dp(i, [1~k,k层, k~j])
    要么鸡蛋碎了,要么鸡蛋不碎
    如果碎了,说明鸡蛋破碎的界限f在1~k-1层,我们就不考虑k到j层了,此时鸡蛋碎了一个还有i-1个鸡蛋,所以变成了求i-1个鸡蛋k-1层最少移动多少次
    如果没碎,说明鸡蛋破碎的界限f在k+1~j层,我们就不考虑1到k层了,此时鸡蛋没碎还有i个鸡蛋,所以变成了求i个鸡蛋j-k层最少移动多少次
for j in range(1, n+1):
   res = float("INF")
   for h in range(1, j+1):
       res = min(res, max(dp[i][j-h], dp[i-1][h-1])+1)
       #加1是因为我们人了一次,进行了一次尝试
   dp[i][j] = res

上述方法的优化 (最大值最小化二分优化)

res = min(res, max(dp[i][j-h], dp[i-1][h-1])+1)

这是一个最大值最小化问题,可以用二分查找
首先明确一点,dp[i]这一层的值是一个递增的序列dp[i][j] <= dp[i][j+c] (c>0)

  • 针对j-h, h是从1~j, 所以dp[i][j-h] 1<=h<=j,是一个递减的序列
  • 针对h-1, h是从1~j, 所以dp[i][h-1] 1<=h<=j,是一个递增的序列
  • 递减的序列就是dp[i][j-h], 递增的序列就是dp[i-1][h-1],横轴是h的取值

在这里插入图片描述

  • 那么max(dp[i][j-h], dp[i-1][h-1])是什么呢?显然是红框的部分
    在这里插入图片描述
  • 那么min(max(dp[i][j-h], dp[i-1][h-1]))是什么呢,显然是这个最低点,既然h从1~j遍历,从这图清晰看出可以使用二分查找,如果

在这里插入图片描述

  • 如果dp[i][j-mid]>dp[i-1][mid-1], 就是左边的虚线情况,说明最低点在mid右边
  • 如果dp[i][j-mid]<dp[i-1][mid-1], 就是右边的虚线情况,说明最低点在mid左边
  • 很符合二分查找了

在这里插入图片描述

完整代码

class Solution:
    def superEggDrop(self, k: int, n: int) -> int:
        """
        dp(k, n) n层k个鸡蛋最少需要移动多少次

        """
        dp = [[0]*(n+1) for _ in range(k+1)]
        dp[1][:] = range(0, n+1)

        for i in range(2, k+1):
            for j in range(1, n+1):
                res = float("INF")
                # for c in range(1, j+1):
                #     res = min(res, max(dp[i][j-c], dp[i-1][c-1])+1) kNN复杂度
                l, r = 1, j
                while(l <= r):
                    m = (l+r) // 2

                    if dp[i][j-m] > dp[i-1][m-1]:
                        l = m + 1
                        res = min(res, dp[i][j-m]) + 1
                    elif dp[i][j-m] < dp[i-1][m-1]:
                        r = m - 1
                        res = min(res, dp[i-1][m-1]) + 1
                    else:
                        res = dp[i-1][m-1] + 1
                        break
                    # res = min(res, max(dp[i][j-m], dp[i-1][m-1])+1)
                dp[i][j] = res
        return dp[k][n]

在这里插入图片描述

逆向思维的DP

原题目求的是k个鸡蛋N层最少需要操作多少次才可以确定f。
转换一下: 求k个鸡蛋最多移动f次,求N的最大值

  • 表示: dp[i][j]: 表示i个鸡蛋,最多移动j次的最大值N

  • 初始状态:

  • 状态转移:

  • dp[k][f]:如果有k个蛋,可以操作f次,所能确定的楼层
    dp[k][f-1]:操作一次后还剩f-1次,蛋碎或者没碎。碎了还有k-1个蛋,没碎还有k个蛋就变成dp[k-1][f-1]
    dp[k][f] = dp[k][f-1] + dp[k-1][f-1] +1
    1:是在某一层掷出,其实我没太懂加1的具体,有点抽象

代码

dp = [[0 for _ in range(n+1)] for _ in range(k+1)]
f = 0
while dp[k][f] < n:
   f += 1
   for i in range(1, k+1):
       dp[i][f] = dp[i][f-1] + dp[i-1][f-1] + 1
return f
空间优化(滚动数组)

dp[i][f] = dp[i][f-1] + dp[i-1][f-1] + 1
第f列只用到了f-1列的数据,所以可以用一维数组

代码
dp = [0 for i in range(k+1)]
f = 0
while dp[k] < n:
    for i in range(k, 0, -1):
        dp[i] = dp[i] + dp[i-1] + 1
    f += 1
return f

至于为什么从后向前遍历:简单解释下

![在这里插入图片描述](https://img-blog.csdnimg.cn/224ab9e1f669459cb27cce9a608e85a4.png

  • 首先明确一点:从dp[k][f],变成dp[k]
  • 每一次for i in range(k, 0, -1): dp[i] = dp[i] + dp[i-1] + 1
    在dp[i] + dp[i-1] + 1还没赋值给dp[i]时,dp[i]保存的时上一轮f,i的值,也就是说
    在dp[i] + dp[i-1] + 1还没赋值给dp[i]时, dp[i]=dp[i][f-1]
    但一旦将dp[i] + dp[i-1] + 1赋值给dp[i]时, dp[i]=dp[i][f], 代表这一轮f的值,上一轮f-1的状态就被覆盖掉了,这也是为什么从后往前遍历的原因

对比一下

dp[i][f] = dp[i][f-1] + dp[i-1][f-1] + 1
dp[i] = dp[i] + dp[i-1] + 1

如果从前向后 ,当i变成i+1时

dp[i+1][f] = dp[i+1][f-1] + dp[i][f-1] + 1

dp[i+1] = dp[i+1] + dp[i] + 1
"""
从前往后问题出在这儿的
dp[i]应该对应二维dp[i][f-1]的值

现在的dp[i]是已经更新的 dp[i] = dp[i] + dp[i-1] + 1
				      dp[i][f] = dp[i][f-1] + dp[i-1][f-1] + 1 不在单纯是dp[i][f-1]的值了,被覆盖了
"""
"""
我们看看从后向前,i变成i-1
dp[i-2]的值应该对应二维dp[i-2][f-1]
而由于从后向前遍历,dp[i-2]的值并没有变化过,所以这里还是对应的二维数组中dp[i-2][f-1]
"""
dp[i-1][f] = dp[i-1][f-1] + dp[i-2][f-1] + 1

dp[i-1] = dp[i-1] + dp[i-2] + 1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1173537.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AD CS证书攻击与防御:ESC1

简介 2021年的BlackHat大会上&#xff0c;Will Schroeder和Lee Christensen发布了关于Active Directory Certificate Services 利用白皮书《Certified Pre-Owned - Abusing Active Directory Certificate Services》。 攻击对象为AD CS&#xff0c;攻击手法主要是利用证书模版…

【算法专题】双指针—和为s的两个数

一、题目解析 只需在这个数组中找出两个数相加等于target即可 二、算法原理 1、暴力解法&#xff08;时间复杂度&#xff1a;O(n^2)&#xff09; 两个for循环嵌套遍历这个数组即可&#xff0c;不过会超时 class Solution { public:vector<int> twoSum(vector<int&…

开启AWS的ubuntu服务器的root用户登录权限

设置root用户密码 输入以下命令修改root用户密码 sudo passwd root输入以下命令切换到root用户 su root仅允许root用户用密码登录 输入以下命令编辑ssh配置文件 vi /etc/ssh/sshd_config新增以下配置允许root用户登录 PermitRootLogin yes把PasswordAuthentication修改为…

latex设置图片的位置

Latex提供了一些命令来控制图片的位置。我们可以通过使用\begin{figure}[位置选项]来控制图片的位置。位置选项可以有h、t、b、p、!这五个&#xff0c;分别表示以下含义&#xff1a; h:表示放在当前位置&#xff0c;不过有时由于论文的格式限制&#xff0c;可能放不下。 t:表示…

详解IPD需求分析工具$APPEALS

够让企业生存下去的是客户&#xff0c;所以&#xff0c;众多企业提出要“以客户为中心”&#xff0c;那如何做到以客户为中心&#xff1f;IPD中给出的答案是需求管理。 需求管理流程&#xff0c;是IPD&#xff08;集成管理开发&#xff09;体系中的四大支撑流程之一&#xff0…

Transformer的最简洁pytorch实现

目录 前言 1. 数据预处理 2. 模型参数 3. Positional Encoding 4. Pad Mask 5. Subsequence Mask 6. ScaledDotProductAttention 7. MultiHeadAttention 8. FeedForward Networks 9. Encoder Layer 10. Encoder 11. Decoder Layer 12. Decoder 13. Transformer 1…

看!MySQL 8.2 数据库支持读写分离啦!

更多文章&#xff0c;欢迎关注作者公众号&#xff0c;欢迎一起交流。 MySQL 8.2.0创新版本已于2023-10-17发布&#xff0c;MySQL Router 8.2 支持数据库的读/写分离&#xff0c;这里将在InnoDB Cluster集群中演示数如何进行读写分离&#xff0c;本篇内容包括&#xff1a;MySQL …

【数字三角形】

题目描述 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径&#xff0c;把路径上面的数加起来可以得到一个和&#xff0c;你的任务就是找到最大的和。 路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外…

逆向学习记录(1)windows系统基本配置

我的环境&#xff1a;win10系统64位。 可以在虚拟机上操作。改天记录一下如何安装虚拟机及里面的系统。 1、查看windows版本情况 按下winr&#xff0c;输入winver&#xff0c;即可。 2、新装的windows系统&#xff0c;桌面上没有我的电脑图标&#xff1f; 在桌面上右键&…

创建基于多任务的并发服务器

有几个请求服务的客户端&#xff0c;我们就创建几个子进程。 这个过程有以下三个阶段&#xff1a; 这里父进程传递的套接字文件描述符&#xff0c;实际上不需要传递&#xff0c;因为子进程会复制父进程拥有的所有资源。 #include <stdio.h> #include <stdlib.h>…

1822_使用python内置的库进行日期序列的生成

使用python的内置的库进行日期序列的生成 用到的库介绍 datetime 实现这样的功能其实只需要这一个库就够了&#xff0c;但是网络上找到的例程很多都额外增加了对time库的引用。只能说&#xff0c;这样不会出现错误&#xff0c;但是这样肯定会有一些计算资源上的消耗。 #!/u…

2023年【山东省安全员C证】考试技巧及山东省安全员C证模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 山东省安全员C证考试技巧考前必练&#xff01;安全生产模拟考试一点通每个月更新山东省安全员C证模拟试题题目及答案&#xff01;多做几遍&#xff0c;其实通过山东省安全员C证模拟考试题很简单。 1、【多选题】《环境…

Leetcode-283 移动零

count记录0的个数&#xff0c;不为0的数取代0位置&#xff0c;最后把剩余位置置零 class Solution {public void moveZeroes(int[] nums) {int count 0;for(int i0;i<nums.length;i){if(nums[i]0){count;}else{nums[i-count]nums[i];}}for(int inums.length-count;i<nu…

最近又考了两个Oracle认证,交一下作业

从Oracle 10g 开始考Oracle的认证&#xff0c;现在已经有15个Oracle的认证了&#xff0c;最近又考了两个Oracle认证&#xff0c;分别是云和AI的。是现在正时髦的技术&#xff0c;又恰恰是我的短板&#xff0c;以考促学&#xff0c;正好系统地学习这两门知识。这两个证书的培训和…

csapp bomb lab part4

csapp bomb lab part4 phase 5 是一个循环&#xff0c;不断累加&#xff0c;访问的地址基于0x4024b0, phase 6 之后更新 汇编 地址计算 寄存器 cl 是 x86 汇编语言中的一个 8 位寄存器&#xff0c;它是 ecx 寄存器的低位部分。 具体来说&#xff0c;x86 架构中的寄存器可…

第一次测试项目该做些什么准备

目录 1、初步进入软件行业的表现和遇到的问题 2、快速融入项目组的普通方法 3、测试人员快速融入项目的非常规方法 一、初步进入软件测试行业的表现和遇到的问题 看到项目模块较多、功能较多&#xff0c;就怕就慌&#xff0c;不知道从什么地方下手理解不了业务&#xff0c;…

ELK极简上手

目录 引言 首先&#xff0c;下载相关的包 其次&#xff0c;安装启动elasticsearch 下一步&#xff0c;安装并启动logstash 最后&#xff0c;安装并启动kibana 进一步的&#xff0c;测试数据的流动 引言 最近整理电脑发现之前的一篇ELK极简入门笔记&#xff0c;现整理发出…

从源码角度解读BetterScroll中maxScrollY的含义

最近在看一个Vue3 Typescript项目&#xff0c;里面有段BetterScroll代码。 if (scroll.value && scroll.value.maxScrollY > -1) { state.manualLoading true await searchMore() state.manualLoading false } 对这个maxScrollY的含义不太明白&#xff0c;官网的解…

【存档】vscode配置latex环境

原来在另一台电脑上找了个教程配了一遍&#xff0c;这次重新配的时候&#xff0c;那个教程作者更新过后&#xff0c;改成只有linux的脚本了&#xff0c;所以存档一下。真香警告, 2023年初的vscodelatex写作 - 知乎 (zhihu.com) 环境&#xff1a; win10/win11vscodelatex work…

Flink源码解析八之任务调度和负载均衡

源码概览 jobmanager scheduler:这部分与 Flink 的任务调度有关。 CoLocationConstraint:这是一个约束类,用于确保某些算子的不同子任务在同一个 TaskManager 上运行。这通常用于状态共享或算子链的情况。CoLocationGroup & CoLocationGroupImpl:这些与 CoLocationCon…