填充书架(leetcode1105)
首先,我们看题干。在题干的最后有一例子,大家先了解下等会我们会说这个例子的作用。
在本题中,我们需要返回最小高度。先来看第一个题例。
在这个题例中,限制宽度为4,我们第一本书厚度为1,高度也为1,但是它没有占满一层,所以,我们将第二本书和第三本书放在一层,正好占满一层。由于,4,5,6书的宽度均为1,他们放在一层后无法占满一层,所以第7本书会被加入进第三层。正好占满一层。所以最大高度为6。
所以,我们的思路为,建立一个动规数组Dp用来存储我们当前所放书的最小高度,然后我们需要去维护这个高度数组,保证 Dp[ i ] 为存放前 i 本书的最小高度。
我们先来模拟一下题例,当第一本书存放时最大高度只能是1。所以当我们来放第二本书时,我们先去让第二本书,单独放在一层此时的最大高度为4,然后,我们在将第二本书与前面的书拆放在一起,此时得到高度为3,维护最优解,所以Dp[ 2 ]为3,当第三本书需要放入时。我们先将第三本书放入单独的一层,此时放入时高度为Dp[ 2 ]再加上第三本书的高度,然后我们再将前面的书本拆下看是否可以与第三本书单开的一层放在一起,然后,由于我们每次都在维护Dp数组的最优性,所以,此时单开的这层的最大高度,加上拆后的最优的Dp高度就为此时Dp当前数组的高度,然后将这个值与我们先开始单开时的最优高度作比较,维护Dp[ i ]的最优即可。
接下来解释一下题干中最后的例子作用,题干中例子的作用为,当我们排到题例中的第四本书时,我们维护的最优高度不会是4,而是5,因为由于题干中说,第一本书不能隔层去与第四本书排在一层。所以,保证了我们递推的正确性。
完整代码如下:
class Solution {
public:
int minHeightShelves(vector<vector<int>>& books, int shelfWidth) {
int n = books.size();
int f[n+1];
f[0] = 0;
for(int i = 1;i <= n;i++)//往前进行拆书,只要当前新开层能放下
{
int w = books[i - 1][0];
int h = books[i - 1][1];
f[i] = f[i - 1] + h;
for(int j = i - 1;j > 0;j--)
{
w += books[j - 1][0];//记录宽度进行比较
if(w > shelfWidth)
{
break;
}
h = max(h,books[j - 1][1]);//计算当前的最大高度
f[i] = min(f[i],f[j - 1] + h);//维护Dp数组的最优解
}
}
return f[n];//返回当前最后一本书的对应最优解即可
}
};