题目
给你一个下标从 0 开始的二维整数数组 questions ,其中 questions[i] = [pointsi, brainpoweri] 。
这个数组表示一场考试里的一系列题目,你需要 按顺序 (也就是从问题 0 开始依次解决),针对每个问题选择 解决 或者 跳过 操作。解决问题 i 将让你 获得 pointsi 的分数,但是你将 无法 解决接下来的 brainpoweri 个问题(即只能跳过接下来的 brainpoweri 个问题)。如果你跳过问题 i ,你可以对下一个问题决定使用哪种操作。
比方说,给你 questions = [[3, 2], [4, 3], [4, 4], [2, 5]] :
如果问题 0 被解决了, 那么你可以获得 3 分,但你不能解决问题 1 和 2 。
如果你跳过问题 0 ,且解决问题 1 ,你将获得 4 分但是不能解决问题 2 和 3 。
请你返回这场考试里你能获得的 最高 分数。
提示:
1 <= questions.length <= 105
questions[i].length == 2
1 <= pointsi, brainpoweri <= 105
思路
对于数组中的每一项,都有两种情况发生:
- 该问题解决
- 该问题放弃
并且对于每一项,接下来他可能接下来处理不同的问题(跳过brainpoweri项到达j后,可能完成j;或忽略j,完成j+1等等),并且最终要求得到一个最值。这很明显可以用动态规划(dp)的思想来进行处理。
dp的核心思想是穷举+消除重复操作
我们可以首先从前向后进行穷举,以[[1,1],[2,2],[3,3],[4,4],[5,5],[6,6],[7,7]]为例,从第一项开始:
若[1,1]执行后,它跳到[3,3],此时它可以接下来执行[3,3],[4,4],[5,5],[6,6],[7,7]
若[1,1]跳过,[2,2]执行,他跳到[5,5],,此时它可以接下来执行[5,5],[6,6],[7,7]
此时我们发现,[5,5],[6,6],[7,7]这三项是重复的,因此我们可以从后向前将每一项的数值进行记录,这样就可以消除重复操作
因为题目是要求取最大值,因此我们记录的是这一项和后面项按规则解决后的最大值。
首先建立数组ans存储i项和后面项按规则解决后的最大值,我们从最后一项进行思考:
作为最后一项len-1,此时最大值只能是questions[len-1][0]本身
往前一项len-2,此时的最大值应该是它本身或者len-1这一项的最大值(因为当问题转到这一项后,可以跳过它解决最后一项去)
到i项,此时的最大值应该是它本身questions[i][0]加上它解决后将要跳转项i+questions[i][1]+1的最大值ans[i+questions[i][1]+1],或者是i的后一项的最大值。
此时状态转移方程为:
代码
class Solution {
public:
long long mostPoints(vector<vector<int>>& questions) {
int len = questions.size();
vector<long long> ans(len+1);
long long maxx = 0;
for(int i=len-1;i>=0;i--){
int num = i+questions[i][1]+1;
if(num<len)
ans[i] = max(ans[num]+questions[i][0], ans[i+1]);
else
ans[i] = max((long long)questions[i][0], ans[i+1]);
maxx = max(maxx, ans[i]);
}
return maxx;
}
};