leetcode-填充书架

189 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

题目描述

给定一个数组 books ,其中 books[i] = [thicknessi, heighti] 表示第 i 本书的厚度和高度。你也会得到一个整数 shelfWidth 。

按顺序 将这些书摆放到总宽度为 shelfWidth 的书架上。

先选几本书放在书架上(它们的厚度之和小于等于书架的宽度 shelfWidth ),然后再建一层书架。重复这个过程,直到把所有的书都放在书架上。

需要注意的是,在上述过程的每个步骤中,摆放书的顺序与你整理好的顺序相同。

例如,如果这里有 5 本书,那么可能的一种摆放情况是:第一和第二本书放在第一层书架上,第三本书放在第二层书架上,第四和第五本书放在最后一层书架上。 每一层所摆放的书的最大高度就是这一层书架的层高,书架整体的高度为各层高之和。

以这种方式布置书架,返回书架整体可能的最小高度。

示例 1: leetcode1105.png 输入: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];
    }
}