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

这里写目录标题

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

题意

链接: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, jwhile(l <= r):m = (l+r) // 2if dp[i][j-m] > dp[i-1][m-1]:l = m + 1res = min(res, dp[i][j-m]) + 1elif dp[i][j-m] < dp[i-1][m-1]:r = m - 1res = min(res, dp[i-1][m-1]) + 1else:res = dp[i-1][m-1] + 1break# res = min(res, max(dp[i][j-m], dp[i-1][m-1])+1)dp[i][j] = resreturn dp[k][n]

在这里插入图片描述

逆向思维的DP(ksqrt(n)复杂度)

原题目求的是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 += 1for 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] + 1f += 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] + 1dp[i+1] = dp[i+1] + dp[i] + 1
"""
从前往后问题出在这儿的
dp[i]应该对应二维dp[i][f-1]的值现在的dp[i]是已经更新的 dp[i] = dp[i] + dp[i-1] + 1dp[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] + 1dp[i-1] = dp[i-1] + dp[i-2] + 1

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

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

相关文章

全球首例无液氦脑磁图辅助下的胶质瘤切除手术顺利完成

近日&#xff0c;在国家重点研发计划“新型无液氦脑磁图系统研发”项目支持下&#xff0c;首都医科大学附属北京天坛医院季楠教授团队完成全球首例无液氦脑磁图运动功能区定位辅助下的胶质瘤切除手术。 手术对一例肿瘤累及运动功能区的年轻女性在术前分别利用无液氦脑磁图仪和功…

14 _ 排序优化:如何实现一个通用的、高性能的排序函数?

几乎所有的编程语言都会提供排序函数,比如C语言中qsort(),C++ STL中的sort()、stable_sort(),还有Java语言中的Collections.sort()。在平时的开发中,我们也都是直接使用这些现成的函数来实现业务逻辑中的排序功能。那你知道这些排序函数是如何实现的吗?底层都利用了哪种排…

如何在苹果Mac系统设置中查看Wi-Fi密码?

在 Mac 上查找保存的 Wi-Fi 密码的最简单方法之一是从系统设置内的高级 Wi-Fi 首选项页面。您可以通过下面的方式访问此页面来查找您保存的 Wi-Fi 密码。 1.在 Mac 上&#xff0c;选取「苹果菜单」选择「系统设置」。 2.从侧边栏中选择「Wi-Fi」&#xff0c;单击「高级」。 3.…

【监控指标】监控系统-prometheus、grafana。容器化部署。go语言 gin框架、gRPC框架的集成

文章目录 一、监控有哪些指标二、prometheus、grafana架构Prometheus 组件Grafana 组件架构优点 三、安装prometheus和node-exporter1. docker pull镜像2. 启动node-exporter3. 启动prometheus 四、promql基本语法五、grafana的安装和使用1. 新建空文件夹grafana-storage&#…

【面试专题】设计模式篇①

1.工厂设计模式 工厂设计模式是一种创建型模式&#xff0c;它提供了一种创建对象的接口&#xff0c;但具体创建的对象类型可以在运行时决定。工厂设计模式主要解决的是创建对象的灵活性问题。 工厂设计模式主要包括简单工厂模式、工厂方法模式和抽象工厂模式三种。 简单工厂…

如何使用 SwiftUI 中新地图框架 MapKit

文章目录 前言MapKit 弃用项MapContentBuilder&#xff08;iOS 17&#xff09;地图交互地图样式地图控件地图相机位置总结 前言 了解 iOS 17 中的 MapKit 后&#xff0c;我们会发现 Apple 引入了更适合 SwiftUI 的 API。 MapKit 弃用项 一旦将你的 App 目标更新到 iOS 17&am…

宠物医院服务预约小程序的效果如何

随着养宠家庭增多及对爱宠的照顾加深&#xff0c;除了食品、服饰外&#xff0c;宠物医院近些年也迎来了较高发展&#xff0c;部分城市甚至聚集着众多品牌&#xff0c;以单店或多店品牌的方式拓展市场。 对宠物医院来说&#xff0c;一般都是拓展同市客户&#xff0c;或者多门店…

OpenFeign 的超时重试机制以及底层实现原理

目录 1. 什么是 OpenFeign&#xff1f; 2. OpenFeign 的功能升级 3. OpenFeign 内置的超时重试机制 3.1 配置超时重试 3.2 覆盖 Retryer 对象 4. 自定义超时重试机制 4.1 为什么需要自定义超时重试机制 4.2 如何自定义超时重试机制 5. OpenFeign 超时重试的底层原理 5…

【蓝桥杯】2023省赛H题

考察知识点&#xff1a;双向链表&#xff0c;小根堆 完整代码在文章末尾 题目 【问题描述】 给定一个长度为 N 的整数数列: A1,A2,...,AN。你要重复以下操作 K 次 :…

下载安装各种版本的Vscode以及解决VScode官网下载慢的问题

下载指定版本 在Vscode官网 Vscode官网更新子页 这里的左侧栏点击其中一个会跳转到某个版本&#xff0c;或者在官网子页 https://code.visualstudio.com/updates的后面跟上需要的版本号即可完成目标版本下载页面的跳转 选择Linux里的ARM包不会自动下载而是跳转到另一个页面 …

【大模型应用开发教程】04_大模型开发整体流程 基于个人知识库的问答助手 项目流程架构解析

大模型开发整体流程 & 基于个人知识库的问答助手 项目流程架构解析 一、大模型开发整体流程1. 何为大模型开发定义核心点核心能力 2. 大模型开发的整体流程1. 设计2. 架构搭建3. Prompt Engineering4. 验证迭代5. 前后端搭建 二、项目流程简析步骤一&#xff1a;项目规划与…

Sync Folders Pro(文件夹数据同步工具)

Sync Folders Pro for Mac 是一款功能强大的文件夹同步工具&#xff0c;旨在帮助用户在 Mac 计算机和移动设备之间创建双向同步。这款软件支持各种文件系统和设备&#xff0c;如 iPhone&#xff0c;iPad&#xff0c;iPod&#xff0c;Android 等。通过这款软件&#xff0c;用户可…

【Spring Security】Spring Security 认证过程源码分析

项目启动 我们在前面有了解到可以在application.yml中配置用户名密码,那么可以猜想:肯定是在项目启动的时候加载的,我们通过鼠标点击 进入SecurityProperties,我们在User中的getName上打断点,这样项目启动的时候就可以走到这里 之后我们通过点击:Drop Frame可以往回走进…

基于白冠鸡算法的无人机航迹规划-附代码

基于白冠鸡算法的无人机航迹规划 文章目录 基于白冠鸡算法的无人机航迹规划1.白冠鸡搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用白冠鸡算法来优化无人机航迹规划。 1.白冠鸡…

Python爬取读书网的图片链接和书名并保存在数据库中

一个比较基础且常见的爬虫&#xff0c;写下来用于记录和巩固相关知识。 一、前置条件 本项目采用scrapy框架进行爬取&#xff0c;需要提前安装 pip install scrapy# 国内镜像 pip install scrapy -i https://pypi.douban.com/simple 由于需要保存数据到数据库&#xff0c;因…

安达发|APS生产排程解决五金制造企业的需求

在五金制造行业中&#xff0c;生产排程一直是一个非常重要的环节。然而&#xff0c;由于五金行业的特点和痛点&#xff0c;传统的生产排程方法往往难以满足企业的需求。本文将针对五金行业的痛点&#xff0c;探讨如何利用APS生产排程解决这些问题。 首先&#xff0c;我们需要了…

JAVA毕业设计109—基于Java+Springboot+Vue的宿舍管理系统(源码+数据库)

基于JavaSpringbootVue的宿舍管理系统(源码数据库)109 一、系统介绍 本系统前后端分离 本系统分为学生、宿管、超级管理员三种角色 1、用户&#xff1a; 登录、我的宿舍、申请调宿、报修申请、水电费管理、卫生检查、个人信息修改。 2、宿管&#xff1a; 登录、用户管理…

为机器学习算法准备数据(Machine Learning 研习之八)

本文还是同样建立在前两篇的基础之上的&#xff01; 属性组合实验 希望前面的部分能让您了解探索数据并获得洞察力的几种方法。您发现了一些数据怪癖&#xff0c;您可能希望在将数据提供给机器学习算法之前对其进行清理&#xff0c;并且发现了属性之间有趣的相关性&#xff0c…

谈一谈SQLite、MySQL、PostgreSQL三大数据库

每一份付出&#xff0c;必将有一份收货&#xff0c;就像这个小小的果实&#xff0c;时间到了&#xff0c;也就会开花结果… 三大数据库概述 SQLite、MySQL 和 PostgreSQL 都是流行的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;但它们在功能、适用场景和性…

Leetcode刷题详解——全排列

1. 题目链接&#xff1a;46. 全排列 2. 题目描述&#xff1a; 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],…