LeetCode410周赛DP +前缀和

单调数组对的数目1

dp[i][j]代表针对arr1[i],选择数字j的情况下,单调数组对数.
因为nums[i]最大只有50,暴力选择每一个j

class Solution:
    def countOfPairs(self, nums: List[int]) -> int:
        MOD = 10 ** 9 + 7
        n = len(nums)
        dp = [[0] * (nums[i] + 1) for i in range(n)]

        # 初始化第一个位置
        for j in range(nums[0] + 1):
            dp[0][j] = 1

        # 动态规划填表
        for i in range(1, n):
            for j in range(nums[i] + 1):
                x = nums[i] - j
                for pre_j in range(j + 1):
                    pre_x = nums[i-1] - pre_j]
                    if pre_x >= x :
                        dp[i][j] += dp[i-1][pre_j]
                    else:break
                dp[i][j] %= MOD
                

        # 结果求和
        result = sum(dp[n - 1]) % MOD
        return result

单调数组对的数目2
nums[i]提高到1000,就不能暴力了
观察T1代码发现,第三重循环是单调的,找到所有pre_j,然后比对pre_x >= x,不满足就退出。我们可以设计算法,O(1)复杂度找出最合适的pre_j,也就是所有满足pre_j的和,需要用前缀和来优化
dp[i][j]代表针对arr1[i]选择所有小于等于j的数字所形成的单调数对

class Solution:
 def countOfPairs(self, nums: List[int]) -> int:
     MOD = 10 ** 9 + 7
     n = len(nums)
     dp = [[0] * (nums[i] + 1) for i in range(n)]

     # 初始化第一个位置
     for j in range(nums[0] + 1):
         dp[0][j] = j + 1

     # 动态规划填表
     for i in range(1, n):
         for j in range(nums[i] + 1):
             x = nums[i] - j # x肯定大于0
             pre_j = nums[i-1] - x # 上一个能选的最大的j
             pre_j = min(pre_j, j) # 有可能pre_j更大,题目规定arr1非递减
             if pre_j < 0:tmp = 0 # 有可能没有pre_j,那么我们也要处理前缀和
             else: tmp = dp[i-1][pre_j]
             if j != 0:
                 dp[i][j] = tmp + dp[i][j-1]
             else: dp[i][j] = tmp
             dp[i][j] %= MOD
     # 结果求和
     result = dp[n - 1][nums[-1]] % MOD
     return result
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值