【限时免费】20天拿下华为OD笔试之【DP】2023B-书籍叠放【闭着眼睛学数理化】全网注释最详细分类最全的华为OD真题题解

【DP】2023B-书籍叠放

题目描述与示例

题目描述

书籍的长、宽都是整数对应(l,w)。如果书A的长宽度都比B长宽大时,则允许将B排列放在A上面。

现在有一组规格的书籍,书籍叠放时要求书籍不能做旋转,请计算最多能有多少个规格书籍能叠放在一起。

输入描述

输入:books = 20,16,15,11,10,10,9,10

说明:总共4本书籍,

第一本长度为20,宽度为16

第二本书长度为15宽度为11

依次类推,最后一本书长度为9,宽度为10

输出描述

输出:3

最多能有多少个规格书籍能叠放在一起

示例一

输入

20,16,15,11,10,10,9,10

输出

3

说明

最多3个规格的书籍可以叠放到一起,从下到上依次为: [20,16],[15,11],[10,10]

示例二

输入

20,15,15,20

输出

1

解题思路

注意:本题和LC354. 俄罗斯套娃信封问题面试题 17.08. 马戏团人塔LC1626. 无矛盾的最佳球队等题目几乎完全一致,属于LC300. 最长递增子序列的轻变形题目。

如何转变为LIS问题

长度严格不等的情况

先考虑一种比较简单的情况,所有书本的长度两两不等,譬如用例

books = [(1, 1), (3, 2), (2, 4), (4, 3)]

我们可以把所有书本按照长度进行排列,得到

books = [(1, 1), (2, 4), (3, 2), (4, 3)]

books进行排序后,单看长度的话,后面位置的书本长度一定大于前面位置的书本长度,即一定存在books[i][0] > books[j][0]对于任何i > j成立。故我们只需要考虑宽度即可,把所有宽度从books数组中提取出来可以得到宽度数组widths

widths = [1, 4, 2, 3]

为了使得叠放的书本尽可能多,子序列就要尽可能长。问题实际上转变为对宽度数组widths考虑最长递增子序列LIS问题,即宽度数组能够取得的LIS长度,就是整个书本数组能够取得的LIS长度。故我们对widths数组进行LIS问题的求解即可。

上述例子可以得到widths的LIS是[1, 2, 3],对应books的LIS是[(1, 1), (3, 2), (4, 3)],长度3即为答案。

长度可能相等的情况

对于书本长度可能相等的情况呢?考虑用例

books = [(1, 1), (2, 3), (4, 4), (2, 2)]

如果我们考虑对长度进行升序排序后,对长度相等的书本根据宽度也进行升序排序,那么会得到

books = [(1, 1), (2, 2), (2, 3), (4, 4)]

提取宽度数组widths得到

widths = [1, 2, 3, 4]

显然此时widths的LIS是[1, 2, 3, 4],长度为4,但其对应的books数组的LIS并不能取[(1, 1), (2, 2), (2, 3), (4, 4)],因为长度同样为2的书本的叠放并不符合要求。

为了避免上述问题,我们考虑对长度进行升序排序后,对长度相等的书本根据宽度进行降序排序,那么会得到

books = [(1, 1), (2, 3), (2, 2), (4, 4)]

提取宽度数组widths得到

widths = [1, 3, 2, 4]

此时widths的LIS是[1, 3, 4]或者[1, 2, 4],对应的books数组的LIS为[(1, 1), (2, 3), (4, 4)]或者[(1, 1), (2, 2), (4, 4)],符合要求。

这是因为对于长度相等的书本而言,更小的宽度被排到更后的位置,这样当我们对宽度考虑LIS问题时,就不会出现长度相等的书籍出现在递增子序列中的情况了。

排序依据

故最终我们选择先依据长度升序,再依据宽度降序的方式,对书本数组books进行排序

books.sort(key = lambda item: (item[0], -item[1]))

dp求解LIS问题

在对书本数组进行排序之后,剩下部分就是对所有书本宽度做常规的LIS问题了,此部分可以参考LC300. 最长递增子序列

我们考虑动态规划三部曲:

  1. dp数组的含义是什么?
  • dp数组是一个长度为n的一维列表,dp[i]表示以第i本书籍为结尾的最长递增子序列的长度
  1. 动态转移方程是什么?
  • 对于第i本书,我们都去考虑其前面的第i-1本书,用索引j表示。如果第i本书的宽度大于第j本书的宽度,即存在books[i][1] > books[j][1]成立,那么i可能可以放在j的后面。
  • 如果选择i放在j的下方能使得i叠放更多书籍,或者说递增子序列能够更长,那么我们选择j
for i in range(1, n)    
    for j in range(i):
        if books[i][1] > books[j][1]:
            dp[i] = max(dp[j]+1, dp[i])
  1. dp数组如何初始化?
  • 以第0本书为结尾的最长递增子序列的长度为1。其余书本对应的最长递增子序列长度也可以默认为1
dp = [1] * n

代码

# 题目:2023B-书籍叠放
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:DP/LIS问题变种
# 代码看不懂的地方,请直接在群上提问


# 输入
lst = list(map(int, input().split(",")))
# 将输入长度为2n的一维列表转化为n*2的二维列表
# books[i] = (第i本书的长度,第i本书的宽度)
books = [(lst[i], lst[i+1]) for i in range(0, len(lst), 2)]
# 对n本书进行排序,先依照长度升序排序,长度相等时依据宽度降序排序
books.sort(key = lambda item: (item[0], -item[1]))
# 获得书本的数量n
n = len(books)

# 初始化dp数组
# dp[i]选择了第i本书籍为底部书籍,能够叠放的最多数目
# 或者说以第i本书籍为结尾的最长递增子序列的长度
dp = [1] * n

# 遍历每一本书籍i
for i in range(1, n):
    # 考虑书籍i之前的所有书籍j
    for j in range(i):
        # 如果书籍i的宽度大于书籍j的宽度
        # 那么书籍j可以放在书籍i的上方
        # 如果选择i放在j的下方能使得i叠放更多书籍
        # 则选择j
        if books[i][1] > books[j][1]:
            dp[i] = max(dp[j]+1, dp[i])

# dp数组中的最大值为能够叠放的最大书籍数目
print(max(dp))

时空复杂度

时间复杂度:O(N^2)。dp过程需要进行双重循环,复杂度为O(N^2)。排序的时间复杂度为O(NlogN)。总的复杂度取其中的较大值,为O(N^2)

空间复杂度:O(N)。dp数组所占空间。

华为OD算法冲刺训练

  • 华为OD算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 30+天陪伴式学习,20+直播课时,300+动画图解视频,200+LeetCode经典题,100+华为OD真题,还有简历修改与模拟面试将为你解锁

  • 可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 sheepvipvip了解更多

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
华为OD机试-2023真题主要考察了以下几个方面的知识点: 1. 数据结构与算法:题目涉及了常见的数据结构和算法,如数组、链表、树、图、排序、搜索等。要求考生熟悉这些数据结构的基本操作和常用算法的实现方法。 2. 编程语言:题目要求使用C++或Java语言完成编程任务,要求考生熟悉相应语言的语法和常用的库函数使用方法。 3. 网络通信:题目涉及了网络通信相关的知识点,如TCP/IP协议、HTTP协议、socket编程等。要求考生了解网络通信的基本概念和实现方式。 4. 操作系统:题目要求考生熟悉操作系统相关的知识,如进程管理、内存管理、文件系统等。要求考生了解操作系统的基本功能和实现原理。 5. 数据库:题目涉及了数据库相关的知识点,如SQL语句的编写、数据库的设计和优化等。要求考生具备数据库的基本操作和设计能力。 6. 设计模式:题目要求考生能够根据给定的需求设计相应的对象和类,并且符合设计模式的原则。要求考生熟悉常见的设计模式和其应用场景。 7. 系统设计与架构:题目要求考生从整体上设计和实现一个系统,并考虑系统的性能、可扩展性等因素。要求考生了解系统设计的基本原则和方法。 以上是华为OD机试-2023真题的一些考点分类。考生在复习备考,可以根据这些考点有针对性地进行习和练习,提升自己的应试能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值