LeetCode 629. K个逆序对数组
Posted zaq19970105
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 629. K个逆序对数组相关的知识,希望对你有一定的参考价值。
题目链接:https://leetcode-cn.com/problems/k-inverse-pairs-array/
题目大意
略。
分析
首先,1~n 这 n 个数所能产生的最大逆序对为 n * (n - 1) / 2 对。
设 dp[i][j] 表示 1~i 能产生 j 对逆序对的排列种数。
这里定义一下如果下标为负数,这一项为 0。
在考虑接下来一个事实:对于序列 1,2,3,4,5 和 2,5,7,9,10,在这个问题下,我可以说这两个序列是等价的,因为产生逆序对的本质是大小关系而不是数实际的大小。
现在考虑状态转移方程。
首先当 j > i * (i - 1) / 2 时,dp[i][j] = 0。
其次当 j = 0 时,dp[i][0] = 1,只有顺着排一种方法。
以上确定了初始状态。
对于其他 dp[i][j],我们如果考虑在队头放第 k 大的数,那么这个数就贡献了 k - 1 对逆序对,剩下的 i - 1 个不同的数就可以转化为子问题,也就是 dp[i - 1][j - k]。
同理我们也可以在队头放其他数,分别求一下贡献,就能得到状态转移方程:$$dp[i][j] = \sum_k = max(0, j - i + 1)^j dp[i - 1][k]$$
仔细观察前后两项的关系可以发现:$$dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][max(0, j - i + 1) - 1]$$
不过不推这个式子也能做,搞个前缀和即可。
代码如下
1 class Solution 2 int dp[2][1007], mod = 1e9 + 7, now = 0; 3 public: 4 int kInversePairs(int n, int k) 5 dp[now][0] = 1; 6 7 for(int i = 1; i <= n; ++i) 8 now = !now; 9 dp[now][0] = 1; 10 for(int j = 1; j <= k; ++j) 11 if(2 * j > i * (i - 1)) break; 12 dp[now][j] = (dp[now][j - 1] + dp[!now][j]) % mod; 13 if(j - i >= 0) dp[now][j] = (dp[now][j] - dp[!now][j - i] + mod) % mod; 14 15 16 17 return dp[now][k]; 18 19 ;
以上是关于LeetCode 629. K个逆序对数组的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 495. 提莫攻击 / 629. K个逆序对数组(动规,不会) / 375. 猜数字大小 II(区间dp)
2021-06-01:K个逆序对数组。给出两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个逆序对的不同的数组的个数。逆序对的定义如下:对于数组的第i个和第 j个元素,如果满
LeetCode692. 前K个高频单词 / 剑指 Offer 50. 第一个只出现一次的字符 / 剑指 Offer 51. 数组中的逆序对 / 2. 两数相加