力扣刷题——3251. 单调数组对的数目 II
考虑arr1
可以取到的数字组合数,从0
到i+1
位置的合法的arr1组合数,可以从0
到i
的组合数得到。因此可以想到用动态规划解决问题,使用一个数组dp[i][j]
代表arr1[i] = j
时,前i + 1
个数字有多少个组合。这样一来,最终的答案即为sum(dp[n-1][0...M]
,其中M
为nums
中最大值。根据这个思路写出一个简单的暴力解法:
class Solution {
public:
int countOfPairs(vector<int>& nums) {
int n = nums.size();
int mod = 1e9 + 7;
vector<vector<int>> dp(n, vector<int>(1001, 0));
for(int v = 0; v <= nums[0]; v++)
{
//因为arr1中第一个数字至少可以取一个0
dp[0][v] = 1;
}
for(int i = 1; i < n; i++)
{
for(int v2 = 0; v2 <= nums[i]; v2++)
{
for(int v1 = 0; v1 <= v2; v1++)
{
//确保当前数字在arr1和arr2中是合法的
if (nums[i - 1] - v1 >= nums[i] - v2 && nums[i] - v2 >= 0)
dp[i][v2] = (dp[i - 1][v1] + dp[i][v2]) % mod;
}
}
}
int res = 0;
for(int i = 0; i < 1001; i++)
{
res = (res + dp[n - 1][i]) % mod;
}
return res;
}
};
但是这样会超时,观察一下代码,发现dp[i][v2]的值,可以进行计算优化。因为nums[i - 1] - v1 >= nums[i] - v2 >= 0
,因此可推得v2 >= nums[i] - nums[i - 1] + v1
,也就是说,可以不必去验证arr2
的合法性。
dp[i][v2]
必然大于等于dp[i - 1][0...max(nums[i] - nums[i - 1])]
,这是由之前的合法对数所得到的。
而当nums[i] - nums[i - 1] > 0
时,还要考虑v2
在区间[nums[i] - nums[i - 1], nums[i] - nums[i - 1] + v1]
上的合法对数。
有实现如下:
class Solution {
public:
int countOfPairs(vector<int>& nums) {
int n = nums.size();
int mod = 1e9 + 7;
vector<vector<int>> dp(n + 1, vector<int>(1001, 0));
for(int v = 0; v <= nums[0]; v++)
{
dp[0][v] = 1;
}
for(int i = 1; i < n; i++)
{
int d = max(0, nums[i] - nums[i - 1]);
for(int v = d; v <= nums[i]; v++)
{
if(v)
dp[i][v] = (dp[i - 1][v - d] + dp[i][v - 1]) % mod;
else
dp[i][v] = dp[i - 1][v - d];//因为用了前缀和的优化方式,从下标0到v-d的这段dp可以这样计算
}
}
int res = 0;
for(int i = 0; i < 1001; i++)
{
res = (res + dp[n - 1][i]) % mod;
}
return res;
}
};