填充书架
dp[ i ] = 放下第i 本书的最小高度
递推公式:要放第 i 本书的时候 假定前面有 j 本书在书架上,j<i ,【 j - i 】之间的书作为最上层的,算出最上层书的最小层数
本题的目的是划分成多个子数组,这类问题,我们需要考虑的是子数组中到底要有几个元素?从哪里开始划分?
所以我们就可以枚举最后一个子数组中的元素个数,或者枚举最后一个子数组的起点 j,这样最后一个子数组为 nums[j…i],长度为 i-j+1
nums[j…i] 需要满足的条件时,元素(厚度)之和 不超过 shelfWidth
因此,定义 dp[i] 为 nums[0…i] 的所有划分方案中 得到的 所有子数组最大高度之和 的最小值
考虑 最后一个子数组是 nums[j…i],j 是所有可能的起点,且 nums[j…i] 元素(厚度)之和 不超过 shelfWidth
那么接下来考虑 这个 j 是需要从 0 到 i 顺序枚举呢 ? 还是 从 i 到 0 倒序枚举呢?.
对于 dp[i],nums[i] 已经确定是 最后一个元素,如果顺序枚举,没法快速知道 nums[j…i] 的厚度之和,也没法快速得到这部分书的最大高度
而如果 倒序枚举 j 从 i 到 0,用变量 w 记录 nums[i…j] 的元素厚度和,用 h 记录 nums[i…j] 的元素最大高度
class Solution {
public:int minHeightShelves(vector<vector<int>>& books, int shelfWidth) {int n=books.size();vector<int>dp(n+1,1000000);dp[0]=0;for(int i=0;i<n;++i){int num=0;int in=0;for(int j=i;j>=0;j--){num+=books[j][0];//下一个就要大于宽度 if(num>shelfWidth){break;}in=max(in,books[j][1]);dp[i+1]=min(dp[i+1],dp[j]+in);}}return dp[n];}
};