For an integer array nums
, an inverse pair is a pair of integers [i, j]
where 0 <= i < j < nums.length
and nums[i] > nums[j]
.
Given two integers n and k, return the number of different arrays consisting of numbers from 1
to n
such that there are exactly k
inverse pairs. Since the answer can be huge, return it modulo 109 + 7
.
Example 1:
Input: n = 3, k = 0 Output: 1 Explanation: Only the array [1,2,3] which consists of numbers from 1 to 3 has exactly 0 inverse pairs.
Example 2:
Input: n = 3, k = 1 Output: 2 Explanation: The array [1,3,2] and [2,1,3] have exactly 1 inverse pair.
Constraints:
1 <= n <= 1000
0 <= k <= 1000
This problem asks to find the number of different arrays of length n
containing numbers from 1 to n
with exactly k
inverse pairs. An inverse pair is a pair (i, j) where 0 <= i < j < n and nums[i] > nums[j]. Since the answer can be very large, we need to compute the result modulo 109 + 7.
The most efficient solution uses dynamic programming along with prefix sum optimization.
State Definition: Let dp[i][j]
represent the number of arrays of length i
with exactly j
inverse pairs.
Base Case: dp[0][0] = 1
(An empty array has 0 inverse pairs). All other dp[i][j]
are initially 0.
Transition: This is the core of the dynamic programming solution. Consider adding the number i+1
to an existing array of length i
with j
inverse pairs. When we insert i+1
into the array, it creates additional inverse pairs depending on its position.
i+1
at position 0, we add i
inverse pairs.i+1
at position 1, we add i-1
inverse pairs.i+1
at position i
, we add 0 inverse pairs.Therefore, the number of arrays of length i+1
with j
inverse pairs is the sum of the number of arrays of length i
with j - (i - k)
inverse pairs, where k
ranges from 0 to i
. This leads to the recurrence relation:
dp[i+1][j] = Σ dp[i][j - (i - k)]
for k
from 0
to i
(with appropriate boundary conditions to handle negative indices and cases where j
is smaller than the subtracted value).
Prefix Sum Optimization: The direct computation of the above summation has a time complexity of O(n*k^2). This can be improved using prefix sums. Let prefixSum[i][j] = Σ dp[i][x]
for x
from 0 to j
. Then we can rewrite the recurrence as:
dp[i+1][j] = prefixSum[i][j] - prefixSum[i][max(0, j - i -1)]
This reduces the computation from O(nk) to O(nk).
Space Optimization: Notice that dp[i+1][j]
only depends on the i
th row. Therefore, we can reduce the space complexity from O(n*k) to O(k) by using a single array for dp
and updating it iteratively.
def kInversePairs(n: int, k: int) -> int:
mod = 10**9 + 7
dp = [0] * (k + 1)
dp[0] = 1
prefixSum = [0] * (k + 2)
prefixSum[1] = 1
for i in range(1, n + 1):
new_dp = [0] * (k + 1)
new_prefixSum = [0] * (k + 2)
for j in range(k + 1):
new_dp[j] = (prefixSum[j + 1] - prefixSum[max(0, j - i + 1)] + mod) % mod
new_prefixSum[1] = new_dp[0]
for j in range(1, k + 1):
new_prefixSum[j + 1] = (new_prefixSum[j] + new_dp[j]) % mod
dp = new_dp
prefixSum = new_prefixSum
return dp[k]
Time Complexity: O(n*k) due to the nested loops in the dynamic programming calculation. The prefix sum calculation is O(k) per row, and we perform this for n rows.
Space Complexity: O(k) because we are using only one array dp
of size k+1 to store the dynamic programming results, and a single array for the prefix sums.
The provided code implements this optimized dynamic programming solution. Other languages (Java, C++, Go, Typescript) can implement the same approach with similar time and space complexities. Remember to handle modulo operations correctly to avoid integer overflow.