一、Problem
附近的家居城促销,你买回了一直心仪的可调节书架,打算把自己的书都整理到新的书架上。
你把要摆放的书 books 都整理好,叠成一摞:从上往下,第 i 本书的厚度为 books[i][0],高度为 books[i][1]。
按顺序 将这些书摆放到总宽度为 shelf_width 的书架上。
先选几本书放在书架上(它们的厚度之和小于等于书架的宽度 shelf_width),然后再建一层书架。重复这个过程,直到把所有的书都放在书架上。
需要注意的是,在上述过程的每个步骤中,摆放书的顺序与你整理好的顺序相同。 例如,如果这里有 5 本书,那么可能的一种摆放情况是:第一和第二本书放在第一层书架上,第三本书放在第二层书架上,第四和第五本书放在最后一层书架上。
每一层所摆放的书的最大高度就是这一层书架的层高,书架整体的高度为各层高之和。
以这种方式布置书架,返回书架整体可能的最小高度。
输入: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 本书不必放在第一层书架上。
提示:
1 <= books.length <= 1000
1 <= books[i][0] <= shelf_width <= 1000
1 <= books[i][1] <= 1000
二、Solution
方法一:暴搜(超时)
- 结束条件:n 本书都放好时
- 本层递归的责任:第 i i i 本书可放入当前层,也可放到下一层。
- 返回值:放入 i i i 本书后的书架的最小高度
class Solution {
int n, maxw, INF = 0x3f3f3f3f, bs[][];
int dfs(int i, int w, int mh) {
if (i == n)
return mh;
int min = INF, t1 = 0;
if (w + bs[i][0] <= maxw) {
t1 = dfs(i+1, w+bs[i][0], Math.max(mh, bs[i][1]));
min = Math.min(min, t1);
}
int t2 = dfs(i+1, bs[i][0], bs[i][1]) + mh;
return Math.min(min, t2);
}
public int minHeightShelves(int[][] books, int shelf_width) {
n = books.length;
bs = books;
maxw = shelf_width;
return dfs(0, 0, 0);
}
}
复杂度分析
- 时间复杂度: O ( 2 n ) O(2^n) O(2n),
- 空间复杂度: O ( n ) O(n) O(n),
方法二:记忆化搜索
加入缓存后可 ac…
class Solution {
int n, maxw, INF = 0x3f3f3f3f, f[], bs[][];
int dfs(int i) {
if (i >= n)
return 0;
if (f[i] != INF)
return f[i];
int m = 0, mh = 0, ans = INF;
for (int j = i; j < n; j++) {
m += bs[j][0];
mh = Math.max(mh, bs[j][1]);
if (m > maxw)
break;
ans = Math.min(ans, dfs(j+1) + mh);
}
return f[i] = ans;
}
public int minHeightShelves(int[][] books, int shelf_width) {
n = books.length;
bs = books;
maxw = shelf_width;
f = new int[n+1];
Arrays.fill(f, INF);
return dfs(0);
}
}
复杂度分析
- 时间复杂度: O ( n 2 ) O(n^2) O(n2),
- 空间复杂度: O ( n ) O(n) O(n),
方法二:dp
- 定义状态:
- f [ i ] f[i] f[i] 表示放入前 i i i 本书所需要的最小书架高度
- 思考初始化:
- f [ 0 ] = 0 , f [ 1... n ] = I N F f[0] = 0,f[1...n] = INF f[0]=0,f[1...n]=INF
- 思考状态转移方程:这是重点,对于后面的书如何决策呢?
- f [ i ] = m i n ( f [ i ] , f [ i − 1 ] + h i ) f[i] = min(f[i],\ f[i-1] + h_i) f[i]=min(f[i], f[i−1]+hi) 放入第 i i i 本书后,如果最大高度大于不放该第 i i i 本书时的书架的最小高度,那么
- 思考输出: f [ n ] f[n] f[n]
Q:枚举
j
j
j 的时候为什么要从后往前枚举呢?
A:这和题目限定条件(每一本书都要按顺序方)有关,但理解地不是很透侧…
class Solution {
public int minHeightShelves(int[][] bs, int shelf_width) {
int n = bs.length, f[] = new int[n+1];
Arrays.fill(f, 0x3f3f3f3f);
f[0] = 0;
for (int i = 0; i < n; i++) {
int w = 0, h = 0;
for (int j = i; j >= 0; j--) {
w += bs[j][0];
h = Math.max(h, bs[j][1]);
if (w > shelf_width)
break;
f[i+1] = Math.min(f[i+1], f[j] + h);
}
}
return f[n];
}
}
复杂度分析
- 时间复杂度: O ( ) O() O(),
- 空间复杂度: O ( ) O() O(),