动态规划:LeetCode.H0629.K个逆序对数组
题目描述
给出两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个逆序对的不同的数组的个数。
逆序对的定义如下:对于数组的第i个和第 j个元素,如果满i < j且 a[i] > a[j],则其为一个逆序对;否则不是。
由于答案可能很大,只需要返回 答案 mod 109 + 7 的值。
示例 1:
示例 2:
说明:
n 的范围是 [1, 1000] 并且 k 的范围是 [0, 1000]。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/k-inverse-pairs-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
在思考中发现一个规律,
假如现在要求 ni
个数的 ki
个逆序对 (假设此时ki
< ni
),那么就是
-
在
ni-1
个数的ki
个逆序对插入ni
这个数字,不需要新增逆序对,将其添加到最后一位即可。即dp[ni-1][ki] += dp[ni-1][ki]
-
在
ni-1
个数的ki-1
个逆序对插入ni
这个数字,使得新增一个逆序对,只需要把ni
插入到最后一个和倒数第二个数的中间就好了,这样ni
只会和之前的最后一个数字形成逆序对。即dp[ni][ki] += dp[ni-1][ki-1]
-
在
ni-1
个数的ki-2
个逆序对中,将ni
插入到倒数第二个数和倒数第三个数的中间。ni
和最后两个数字形成逆序对。即dp[ni][ki] += dp[ni-1][ki-2]
.....
以此类推,可以得到
当 ki
< ni
时,
f(ni)(ki) = f(ni-1)(0) + f(ni-1)(1) + f(ni-1)(2) + ... + f(ni-1)(ki-1) + f(ni-1)(ki)
同理,由于 f(ni)(ki-1) = f(ni-1)(0) + ... + f(ni-1)(ki-1)
得:f(ni)(ki) = f(ni)(ki-1) + f(ni-1)(ki)
但是还有特殊情况,ki
大于 ni
时,将ni
插入f(ni-1)(0)、...、f(ni-1)(ki-ni)的第一位都不够满足 ki
的对数要求,那么需要将上述公式减去不能满足的个数
也就是f(ni)(ki) 应该从 f(ni-1)(ki-ni+1) 开始算起
即: f(ni)(ki) = f(ni-1)(ki-ni+1) + ... + f(ni-1)(ki-1) + f(ni-1)(ki)
同理,f(ni)(ki-1) = f(ni-1)(ki-ni) + ... + f(ni-1)(ki-1)
得:f(ni)(ki)= f(ni)(ki-1) - f(ni-1)(ki-ni) + f(ni-1)(ki)
综合两种情况,得到状态转移方程为:f(ni)(ki)= f(ni)(ki-1) - (ki>=ni?f(ni-1)(ki-ni):0) + f(ni-1)(ki)
反思错误
1、一开始没有考虑到 ki 大于 ni 的情况,导致数量过多
2、一开始使用 mod 求余,但是有出现数值为负数的情况,由于减的数量没有到达求余等级,但是加的数量求过余了,这样就变成负数了。后来使用加减来求余
Java代码
执行结果
耗时:14ms,内存:35.3MB
__EOF__

本文链接:https://www.cnblogs.com/casoli/p/16022526.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)