思路分析:同样的题如果是找一个段使奖品最多就很好求解,
对上述情况进行展开:使用滑动窗口对数组中每个长为k的段进行求和算出最多的一个,流程大致为先计算下标0->k-1的和,然后往后加data[k]-data[1], 由一个记录变量来记录当前值和前面所有情况的最大值较大的一个。
上面已经知道一个段怎么找了,但我们需要的是两个段,如何把情况约束成上面情况呢,
分析:设想如果直接假定第二个段的位置为Left->Left+k,这样子是不是就能把第一个段约束在下标0-Left-1内呢,现在第一个段就可以当成处理完毕了(利用滑动窗口),假定的位置,既然是假定当然应该考虑所有情况即取0->k和size-k-1->size-1都应考虑到。
接下来就是可行性的考量
质疑起点
对于第二个段理论上肯定是可以取0的,即总共就k个数据的情况,往后都是给第一段留了“余地”的的情况,毋庸置疑也是可行的。
质疑k
那有没有可能第二个段取不到k个呢,例如当k=1,此时一个线段可以拿两个点的礼物,最多的是倒数第三个和倒数第二个 然后是倒数第一个最多, 显然也是不可能的,最后三个最多的话,此时完全可以取后四个(第一段取倒三倒四,第二段取倒一倒二)多一个倒四完全正受益,其他情况同理
理论成立
利用一个一维数组存储,要是当前位置是第二个段的起点Left时,第一个段能拿的最大值,考虑细节进行编码,参考leetcode官方题解进行了优化(官方真细)
代码
class Solution {
public:
int maximizeWin(vector<int>& prizePositions, int k) {
int size=prizePositions.size(),res=0;
vector<int> dp(size+1);
for(int l=0,r=0;r<=size-1;r++){
while(prizePositions[r]-prizePositions[l]>k){l++;}
res=max(dp[l]+r-l+1,res);
dp[r+1]=max(dp[r],r-l+1);
}
return res;
}
};
结语:分析阶段 大胆猜想 小心求证。