当前位置: 首页 > news >正文

【Leetcode 每日一题】3250. 单调数组对的数目 I

问题背景

给你一个长度为 n n n 整数数组 n u m s nums nums
如果两个 非负 整数数组 ( a r r 1 , a r r 2 ) (arr_1, arr_2) (arr1,arr2) 满足以下条件,我们称它们是 单调 数组对:
两个数组的长度都是 n n n

  • a r r 1 arr_1 arr1 是单调 非递减 的,换句话说 a r r 1 [ 0 ] ≤ a r r 1 [ 1 ] ≤ . . . ≤ a r r 1 [ n − 1 ] arr_1[0] \le arr_1[1] \le ... \le arr_1[n - 1] arr1[0]arr1[1]...arr1[n1]
  • a r r 2 arr_2 arr2 是单调 非递增 的,换句话说 a r r 2 [ 0 ] ≤ a r r 2 [ 1 ] ≤ . . . ≤ a r r 2 [ n − 1 ] arr_2[0] \le arr_2[1] \le ... \le arr_2[n - 1] arr2[0]arr2[1]...arr2[n1]
  • 对于所有的 0 ≤ i ≤ n − 1 0 \le i \le n - 1 0in1 都有 a r r 1 [ i ] + a r r 2 [ i ] = = n u m s [ i ] arr_1[i] + arr_2[i] == nums[i] arr1[i]+arr2[i]==nums[i]

请你返回所有 单调 数组对的数目。
由于答案可能很大,请你将它对 1 0 9 + 7 10 ^ 9 + 7 109+7 取余 后返回。

数据约束

  • 1 ≤ n = n u m s . l e n g t h ≤ 2000 1 \le n = nums.length \le 2000 1n=nums.length2000
  • 1 ≤ n u m s [ i ] ≤ 50 1 \le nums[i] \le 50 1nums[i]50

解题过程

周赛三四题的水准,两道题目只在数据规模上有差异,目前只能尝试写灵神题解的解释。
这题虽然对两个数组有要求,但是实际上只需要枚举其中一个数组的情况,把对另外一个数组中元素的要求当成约束就行。
根据动态规划缩小问题规模的思想:

  • 原问题是下标 0 0 0 n − 1 n - 1 n1中的单调数组对的个数,且 a r r 1 [ n − 1 ] = j = 0 , 1 , 2 , . . . , n u m s [ n − 1 ] arr_1[n−1] = j = 0, 1, 2, ..., nums[n - 1] arr1[n1]=j=0,1,2,...,nums[n1]
  • 子问题是下标 0 0 0 i i i 中的单调数组对的个数,且 a r r 1 [ i ] = j arr_1[i] = j arr1[i]=j,将其记作 d p [ i ] [ j ] dp[i][j] dp[i][j]

k k k表示 a r r 1 [ i − 1 ] arr_1[i−1] arr1[i1],那么根据约束条件: { a r r 1 [ i − 1 ] ≤ a r r 1 [ i ] a r r 2 [ i − 1 ] ≥ a r r 2 [ i ] \ \begin{cases} arr_1[i - 1] \le arr_1[i] \\ arr_2[i - 1] \ge arr_2[i] \\ \end{cases}  {arr1[i1]arr1[i]arr2[i1]arr2[i],即 { k ≤ j n u m s [ i − 1 ] − k ≥ n u m s [ i ] − j \ \begin{cases} k \le j \\ nums[i - 1] - k \ge nums[i] - j \\ \end{cases}  {kjnums[i1]knums[i]j,可以得到 k k k 的上界。
解得 k ≤ m i n ( j , n u m s [ i − 1 ] − n u m s [ i ] + j ) = j + m i n ( n u m s [ i − 1 ] − n u m s [ i ] , 0 ) k \le min(j, nums[i - 1] - nums[i] + j) = j + min(nums[i - 1] - nums[i], 0) kmin(j,nums[i1]nums[i]+j)=j+min(nums[i1]nums[i],0),由于所有数组中的元素都是非负的,而 n u m s [ i ] = a r r 1 [ i ] + a r r 2 [ i ] nums[i] = arr_1[i] + arr_2[i] nums[i]=arr1[i]+arr2[i],所以 k ≤ n u m s [ i − 1 ] k \le nums[i - 1] knums[i1]
m a x K = j + m i n ( n u m s [ i − 1 ] − n u m s [ i ] , 0 ) maxK = j + min(nums[i - 1] - nums[i], 0) maxK=j+min(nums[i1]nums[i],0),那么 d p [ i ] [ j ] = { 0 , m a x K < 0 Σ k = 0 m a x K d p [ i − 1 ] [ k ] , m a x K ≥ 0 dp[i][j] = \begin{cases} 0,& maxK \lt 0 \\ \mathop{\Sigma} \limits _ {k = 0} ^ {maxK} dp[i - 1][k],& maxK \ge 0 \\ \end{cases} dp[i][j]= 0k=0ΣmaxKdp[i1][k]maxK<0maxK0
这里 Σ k = 0 m a x K d p [ i − 1 ] [ k ] \mathop{\Sigma} \limits _ {k = 0} ^ {maxK} dp[i - 1][k] k=0ΣmaxKdp[i1][k] 表示对所有的 k k k 0 0 0 m a x K maxK maxK 的情况,求下标 0 0 0 i − 1 i - 1 i1 中的单调数组对的个数之和,要求 a r r 1 = k arr_1 = k arr1=k。这显然满足前缀和的定义,记 s [ j ] = Σ k = 0 j d p [ i − 1 ] [ k ] s[j] = \mathop{\Sigma} \limits _ {k = 0} ^ {j} dp[i - 1][k] s[j]=k=0Σjdp[i1][k],那么上述状态转移方程 ( 3 ) (3) (3) 可以简化为 d p [ i ] [ j ] = { 0 , m a x K < 0 s [ m a x K ] , m a x K ≥ 0 dp[i][j] = \begin{cases} 0,& maxK \lt 0 \\ s[maxK],& maxK \ge 0 \\ \end{cases} dp[i][j]={0s[maxK]maxK<0maxK0
初始值 d p [ 0 ] [ j ] = 1 dp[0][j] = 1 dp[0][j]=1,其中 j = 0 , 1 , 2 , . . . , n u m s [ 0 ] j = 0, 1, 2, ..., nums[0] j=0,1,2,...,nums[0]。这表示的是,下标 0 0 0 0 0 0 中的单调数组对的个数,也就是只考虑数组中第一个元素的情况, a r r 1 [ i ] arr_1[i] arr1[i] 可以是合法范围内任意值。

后续还有进一步优化,目前一下子掌握不了,先暂时放弃。

具体实现

class Solution {// 根据题意定义模数private static final int MOD = 1000000007;public int countOfPairs(int[] nums) {int n = nums.length;// m 表示 nums 数组中的最大值,所有数组中的元素都不会超过这个范围,也就是应枚举的最大值int m = Arrays.stream(nums).max().getAsInt();long [][] dp = new long[n][m + 1];long[] preSum = new long[m + 1];// 填充初始值,只考虑数组中第一个元素的情况Arrays.fill(dp[0], 0, nums[0] + 1, 1);for(int i = 1; i < n; i++) {// 计算前缀和,这是它的定义preSum[0] = dp[i - 1][0];for(int k = 1; k <= m; k++) {preSum[k] = (preSum[k - 1] + dp[i - 1][k]) % MOD;}for(int j = 0; j <= nums[i]; j++) {int maxK = j + Math.min(nums[i - 1] - nums[i], 0);dp[i][j] = maxK >= 0 ? preSum[maxK] % MOD : 0;}}// 答案是考虑完数组中最后一个元素之后,对所有可能情形求和return (int) (Arrays.stream(dp[n - 1], 0, nums[n - 1] + 1).sum() % MOD);}
}
http://www.lryc.cn/news/494210.html

相关文章:

  • 较类中的方法和属性比较
  • nVisual可视化资源管理工具
  • 自动类型推导(auto 和 decltype)
  • 新型大语言模型的预训练与后训练范式,谷歌的Gemma 2语言模型
  • 基于投影寻踪博弈论-云模型的滑坡风险评价
  • WRF-Chem模式安装、环境配置、原理、调试、运行方法;数据准备及相关参数设置方法
  • Spring中每次访问数据库都要创建SqlSession吗?
  • 力扣刷题TOP101:6.BM7 链表中环的入口结点
  • 浅谈telnet和ping
  • P4-3【应用数组进行程序设计 | 第三节】——知识要点:字符数组
  • 彻底理解微服务配置中心的作用
  • SpringBoot开发——详细讲解 Spring Boot 项目中的 POM 配置
  • pyspark实现基于协同过滤的电影推荐系统
  • 视觉语言模型(VLM)学习笔记
  • 学习笔记:黑马程序员JavaWeb开发教程(2024.11.29)
  • 文档加密怎么做才安全?
  • 使用Setup Factory将C#的程序打包成安装包
  • 解决 java -jar 报错:xxx.jar 中没有主清单属性
  • Java HashSet 介绍
  • 2024年几款免费的AI对话工具介绍
  • Gazebo构建模型(含GNSS、IMU、LiDAR、Camera传感器)
  • #Js篇: 链式判断运算符 ?.和Null判断运算符 ??和逻辑赋值运算符||= = ??=
  • IDEA敲Web前端快捷键
  • 【Vue3】【Naive UI】<NDropdown>标签
  • 技术总结(四十一)
  • Android布局
  • k8s集成skywalking
  • 如何写一份优质技术文档
  • LeetCode:206.反转链表
  • 详解高斯消元