【区间 dp】A017_LC_填充书架(暴搜 / 记忆化搜索 / dp(疑惑))

一、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 本书后的书架的最小高度
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 ( 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 ( n ) O(n)

方法二:dp

  • 定义状态
    • f [ i ] f[i] 表示放入前 i i 本书所需要的最小书架高度
  • 思考初始化:
    • f [ 0 ] = 0 f [ 1... n ] = I N F 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) 放入第 i i 本书后,如果最大高度大于不放该第 i i 本书时的书架的最小高度,那么
  • 思考输出 f [ n ] f[n]

Q:枚举 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()

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/106932830