LeetCode 题解工作台
统计逆序对的数目
给你一个整数 n 和一个二维数组 requirements ,其中 requirements[i] = [end i , cnt i ] 表示这个要求中的末尾下标和 逆序对 的数目。 整数数组 nums 中一个下标对 (i, j) 如果满足以下条件,那么它们被称为一个 逆序对 : i 且 nums[…
2
题型
5
代码语言
3
相关题
当前训练重点
困难 · 状态·转移·动态规划
答案摘要
我们定义 表示 的排列中,逆序对数量为 的排列数。考虑下标为 的数 与前面 个数的大小关系。如果 比前面 个数小,那么前面的 个数与 都构成了逆序对,逆序对数量为 。因此,我们可以得到状态转移方程: $$
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路
题目描述
给你一个整数 n 和一个二维数组 requirements ,其中 requirements[i] = [endi, cnti] 表示这个要求中的末尾下标和 逆序对 的数目。
整数数组 nums 中一个下标对 (i, j) 如果满足以下条件,那么它们被称为一个 逆序对 :
i < j且nums[i] > nums[j]
请你返回 [0, 1, 2, ..., n - 1] 的 排列 perm 的数目,满足对 所有 的 requirements[i] 都满足 perm[0..endi] 中恰好有 cnti 个逆序对。
由于答案可能会很大,将它对 109 + 7 取余 后返回。
示例 1:
输入:n = 3, requirements = [[2,2],[0,0]]
输出:2
解释:
两个排列为:
[2, 0, 1]- 前缀
[2, 0, 1]的逆序对为(0, 1)和(0, 2)。 - 前缀
[2]的逆序对数目为 0 个。
- 前缀
[1, 2, 0]- 前缀
[1, 2, 0]的逆序对为(0, 2)和(1, 2)。 - 前缀
[1]的逆序对数目为 0 个。
- 前缀
示例 2:
输入:n = 3, requirements = [[2,2],[1,1],[0,0]]
输出:1
解释:
唯一满足要求的排列是 [2, 0, 1] :
- 前缀
[2, 0, 1]的逆序对为(0, 1)和(0, 2)。 - 前缀
[2, 0]的逆序对为(0, 1)。 - 前缀
[2]的逆序对数目为 0 。
示例 3:
输入:n = 2, requirements = [[0,0],[1,0]]
输出:1
解释:
唯一满足要求的排列为 [0, 1] :
- 前缀
[0]的逆序对数目为 0 。 - 前缀
[0, 1]没有逆序对。
提示:
2 <= n <= 3001 <= requirements.length <= nrequirements[i] = [endi, cnti]0 <= endi <= n - 10 <= cnti <= 400- 输入保证至少有一个
i满足endi == n - 1。 - 输入保证所有的
endi互不相同。
解题思路
方法一:动态规划
我们定义 表示 的排列中,逆序对数量为 的排列数。考虑下标为 的数 与前面 个数的大小关系。如果 比前面 个数小,那么前面的 个数与 都构成了逆序对,逆序对数量为 。因此,我们可以得到状态转移方程:
由于题目要求 的逆序对数量为 ,因此,当我们计算 时,我们只需要计算 即可。其余的 都为 。
时间复杂度 ,空间复杂度 。其中 是逆序对数量的最大值。本题中 。
class Solution:
def numberOfPermutations(self, n: int, requirements: List[List[int]]) -> int:
req = [-1] * n
for end, cnt in requirements:
req[end] = cnt
if req[0] > 0:
return 0
req[0] = 0
mod = 10**9 + 7
m = max(req)
f = [[0] * (m + 1) for _ in range(n)]
f[0][0] = 1
for i in range(1, n):
l, r = 0, m
if req[i] >= 0:
l = r = req[i]
for j in range(l, r + 1):
for k in range(min(i, j) + 1):
f[i][j] = (f[i][j] + f[i - 1][j - k]) % mod
return f[n - 1][req[n - 1]]
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | Depends on the final approach |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
Candidate understands the concept of dynamic programming for state transitions.
- question_mark
Candidate can efficiently calculate and update inversion counts using data structures like Fenwick Tree.
- question_mark
Candidate identifies the challenge of handling multiple requirements and can incorporate them into the DP approach.
常见陷阱
外企场景- error
Not accounting for all inversion constraints, which can lead to incorrect permutation counts.
- error
Inefficient inversion counting leading to excessive time complexity.
- error
Failure to properly update the DP table when new elements are added, causing incorrect counts of valid permutations.
进阶变体
外企场景- arrow_right_alt
Modify the problem to handle permutations with additional constraints on element values.
- arrow_right_alt
Add a requirement to count the number of inversions for subsets of the array, not just prefixes.
- arrow_right_alt
Allow the inversion count to be variable for each prefix, testing how the algorithm handles different ranges of inversion constraints.