力扣刷题——3251. 单调数组对的数目 II

考虑arr1可以取到的数字组合数,从0i+1位置的合法的arr1组合数,可以从0i的组合数得到。因此可以想到用动态规划解决问题,使用一个数组dp[i][j]代表arr1[i] = j时,前i + 1个数字有多少个组合。这样一来,最终的答案即为sum(dp[n-1][0...M],其中Mnums中最大值。根据这个思路写出一个简单的暴力解法:

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;
    }
};
posted @ 2024-11-29 17:30  SuzumiyaYui  阅读(3)  评论(0编辑  收藏  举报