不得不说我在做题上的运气真是一直都很背。
这题拿到手按照所有情况来看就是全排列。这里题目虽然说了一盆花不强制播种时间必须连续,但为了结果最优,那肯定是连续更好。因为如果一盆花a播种一半再去播种另一盆b再回头播种a的方案的效果肯定差于:先播种完b再播种a的方案。这里我列举的情况比较单一。从感性的分析来看你播种一半再去干其他的其实不能带来任何收益(先播种完的话可以先长好)。现在问题就简化了,就是说要播种那一盆花就一次播种完。
单调栈一般不在排列上做文章,所以单调栈pass。
动态规划的话,还是逃不过顺序这一个问题,比方每新加入一种花,给它安排位置的话也得知道前面的状态的顺序,这样状态过多就没办法存储了。所以动态规划pass(我认为是不行,不排除有大佬可以想出什么好办法)。
看顺序的话就是排序和优先队列了。
先看看排序,我是先按照播种时间从大到小排序写了一发(是我大脑短路了),连样例都没过。
然后想的是:如果顺序定下来了,怎么计算呢?能不能从计算的过程找到一点思路呢?
比方现在计算第3盆花长好的时间t3,那么t3=sum(1-3盆花的播种时长)+第3盆花的生长时长。同理:第4盆花长好的时间t4,那么t4=sum(1-4盆花的播种时长)+第4盆花的生长时长。可以看出对于第x盆花,sum(1-x盆花的播种时长)前面这一项一定是单增的(就是前缀和嘛),而第x盆花的生长时长不确定。那么我们给生长时长从大到小排序的话,可以达到前一项的最大值加后一项的最小值的效果。我也知道这个想法不严谨,只能算一种感性的指引,就这么排了个序结果就过了。
那么现在就证明一下为什么给生长时长从大到小排序是对的。可以先想简单一点的情况,比方我们现在只考虑相邻的两盆花i,i+1交换顺序会有怎样的效果。可以确定的是这两个顺序的交换不会影响i之前的花和i+1之后的花的计算。因为这些项的前缀和没变嘛。
比方第i盆花的播种时长:a,生长时长:c。
第i+1盆花的播种时长:b,生长时长:d。
第i盆花之前的播种时长前缀和为sum。
那么交换之前i和i+1的开花时间:sum+a+c, sum+c+d+b.
交换之后i和i+1的开花时间:sum+b+d, sum+d+c+a
可以看出:
sum+d+c+a>sum+a+c
sum+c+d+b>sum+b+d
所以比较sum+d+c+a和sum+c+d+b就完事了。就是说比较a和b的大小。
选a和b较小的放在i+1的位置上就行了。
现在证明了相邻两盆花的顺序怎么排一定会更优。
说到相邻排序,不知道有没有想到冒泡排序呀。按照冒泡排序生长时长从大到小排序不就可以证明这样是最优的了。就只是大小的比较对象变了。
c++代码如下(年底冲业绩):
struct Bag{
int p,g;
friend bool operator <(Bag a,Bag b)
{
return a.g>b.g;
}
};
class Solution {
public:
Bag bag[100010];
int earliestFullBloom(vector<int>& plantTime, vector<int>& growTime) {
int n=plantTime.size();
for(int i=0;i<n;i++)
{
bag[i].p=plantTime[i];
bag[i].g=growTime[i];
}
sort(bag,bag+n);
int ret=0;
int sum=0;
for(int i=0;i<n;i++)
{
sum+=bag[i].p;
ret=max(ret,sum+bag[i].g);
}
return ret;
}
};