5982. 解决智力问题
倒序DP
可以记dp[i]为从[i, n-1]范围内得到的最高分数,那么反向遍历questions,对于每个i来说,有两种情况:
- 不解决此问题:dp[i] = dp[i + 1]
- 解决此问题,需要跳过后面一些问题,记下一个能够做的问题的下标为j,j = i + brainpower_i + 1:
- 如果j大于n的话,那么后面的问题都不能做,dp[i] = point_i
- 如果j小于n的话,dp[i] = point[i] + dp[j]
class Solution {
public:
long long mostPoints(vector<vector<int>> &questions) {
int n = questions.size();
vector<long long> dp(n + 1);
for(int i = n - 1; i >= 0; i--) {
auto &q = questions[i];
int j = i + q[1] + 1;
dp[i] = max(dp[i + 1], q[0] + (j < n ? dp[j] : 0));
}
return dp[0];
}
};
正序刷表
另一种做法是刷表法:用当前状态,去更新当前状态所影响的状态。
定义 f[i] 表示解决区间 [0,i] 内的问题可以获得的最高分数。
对于问题 i,若跳过,则可以更新f[i+1]=max(f[i+1], f[i])
。
若不跳过,记 j=i + brainpower[i] + 1,则可以更新f[j]=max(f[j], f[i]+point[i])
。
对于 i=n−1 和 j≥n 的情况,为了简化代码逻辑,我们可以将其更新到 f[n] 中。
最后答案为 f[n]。class Solution {
public:
long long mostPoints(vector<vector<int>> &questions) {
int n = questions.size();
vector<long long> f(n + 1);
for (int i = 0; i < n; ++i) {
f[i + 1] = max(f[i + 1], f[i]);
auto &q = questions[i];
int j = min(i + q[1] + 1, n);
f[j] = max(f[j], f[i] + q[0]);
}
return f[n];
}
};