Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
题目描述
给定一个数组 books ,其中 books[i] = [thicknessi, heighti] 表示第 i 本书的厚度和高度。你也会得到一个整数 shelfWidth 。
按顺序 将这些书摆放到总宽度为 shelfWidth 的书架上。
先选几本书放在书架上(它们的厚度之和小于等于书架的宽度 shelfWidth ),然后再建一层书架。重复这个过程,直到把所有的书都放在书架上。
需要注意的是,在上述过程的每个步骤中,摆放书的顺序与你整理好的顺序相同。
例如,如果这里有 5 本书,那么可能的一种摆放情况是:第一和第二本书放在第一层书架上,第三本书放在第二层书架上,第四和第五本书放在最后一层书架上。 每一层所摆放的书的最大高度就是这一层书架的层高,书架整体的高度为各层高之和。
以这种方式布置书架,返回书架整体可能的最小高度。
示例 1:
输入:books = [[1,1],[2,3],[2,3],[1,1],[1,1],[1,1],[1,2]], shelf_width = 4
输出:6
解释:
3 层书架的高度和为 1 + 3 + 2 = 6 。
第 2 本书不必放在第一层书架上。
思路
动态规划的题目,难点还是在状态定义和状态转义方程。
状态定义
定义一维数组dp,dp[i]代表从下标0到小标i的书本,组成书架的最小高度。
状态转移方程
注意题目中一个重要的条件,“摆放书的顺序与你整理好的顺序相同”,即书本必须按照顺序来放,不可以打乱顺序。如果已经求解了dp[0]~dp[i-1],求dp[i],我们考虑这么几种情况:
- book[i]单独成为1层
- book[i]、book[i-1]组成1层
- book[i]、book[i-1]、book[i-2]组成1层
- ...
- book[i]、book[i-1]、book[i-2]、...book[0]组成1层
上面是book[i]所有可能的摆放情况了,那么dp[i]就是上面所有情况的最小值。
- book[i]单独成为1层 dp[i] = dp[i-1] + book[i][1]
- book[i]、book[i-1]组成1层 dp[i] = dp[i-2] + max(book[i][1],book[i-1][1]) ... 一次类推。 当然,还有另外一个限制条件就是书本的厚度,我们在遍历的过程中,要保证在1层的书厚度之和不能超过shelfWidth。
边界条件
dp[0] = books[0][1]
即如果只有一本书的话,它本身的高度就是
Java版本代码
class Solution {
public int minHeightShelves(int[][] books, int shelfWidth) {
int num = books.length;
int[] dp = new int[num];
dp[0] = books[0][1];
for (int i = 1; i < num; i++) {
dp[i] = dp[i-1] + books[i][1];
int width = books[i][0];
int height = books[i][1];
for (int j = i-1; j >= 0; j--) {
width += books[j][0];
if (width > shelfWidth) {
break;
}
height = Integer.max(height, books[j][1]);
if (j >= 1) {
dp[i] = Integer.min(dp[i], height + dp[j-1]);
} else {
dp[i] = Integer.min(dp[i], height);
}
}
}
return dp[num-1];
}
}