1
+ // Runtime : 185 ms (Top 92.81 % ) | Memory : 17.30 MB (Top 67.63 % )
2
+
1
3
class Solution :
4
+ # A very good description of the dp solution is at
5
+ # https://leetcode.com/problems/k-inverse-pairs-array/solution/
6
+ # The code below uses two 1D arrays--dp and tmp--instead if a
7
+ # 2D array. tmp replaces dp after each i-iteration.
2
8
def kInversePairs (self , n : int , k : int ) -> int :
3
- # Complexity:
4
- # - Time: O(N*K)
5
- # - Space: O(K)
6
-
7
- # Special cases that can be short-circuited right away
8
- # - For k=0, there's only one solution, which is having the numbers in sorted order
9
- # DP(n, 0) = 1
10
- if k == 0 :
11
- return 1
12
- # - There can't be more than n*(n-1)/2 inverse pairs, which corresponds to the numbers in reverse order
13
- # DP(n, k) = 0 for all k > n*(n-1)/2
14
- if k > n * (n - 1 ) // 2 :
15
- return 0
16
-
17
- # For the general case, we notice that:
18
- # DP(n+1, k) = sum(DP(n, i) for i in [max(0, k-n), k])
19
- # i.e., adding an additional number (the biggest one n+1):
20
- # - We can have it at the end, in which case it doesn't create any reverse pairs,
21
- # and so the number of configurations with k reverse pairs is DP(n,k)
22
- # - Or we can have it one before the end, in which case it creates exactly reverse pairs,
23
- # and so the number of configurations with k reverse pairs is DP(n,k-1)
24
- # - And so on and so forth, such that having it `i` places before the end create exactly `i` reverse pairs,
25
- # and so the number of configurations with k reverse pairs is DP(n,k-i)
26
- # This relationship allows us to compute things iteratively with a rolling window sum
27
- kLine = [0 ] * (k + 1 )
28
- kLine [0 ] = 1
29
- previousKLine = kLine .copy ()
30
- maxFeasibleK = 0
31
- for m in range (2 , n + 1 ):
32
- previousKLine , kLine = kLine , previousKLine
33
- rollingWindowSum = 1
34
- maxFeasibleK += m - 1
35
- endKLineIdx = min (k , maxFeasibleK ) + 1
36
- intermediateKLineIdx = min (endKLineIdx , m )
37
- for kLineIdx in range (1 , intermediateKLineIdx ):
38
- rollingWindowSum = (rollingWindowSum + previousKLine [kLineIdx ]) % _MODULO
39
- kLine [kLineIdx ] = rollingWindowSum
40
- for kLineIdx in range (intermediateKLineIdx , endKLineIdx ):
41
- rollingWindowSum = (rollingWindowSum + previousKLine [kLineIdx ] - previousKLine [kLineIdx - m ]) % _MODULO
42
- kLine [kLineIdx ] = rollingWindowSum
43
- return kLine [k ]
44
-
45
-
46
- _MODULO = 10 ** 9 + 7
9
+ dp , mod = [1 ]+ [0 ] * k , 1000000007
10
+
11
+ for i in range (n ):
12
+ tmp , sm = [], 0
13
+ for j in range (k + 1 ):
14
+ sm += dp [j ]
15
+ if j - i >= 1 : sm -= dp [j - i - 1 ]
16
+ sm %= mod
17
+ tmp .append (sm )
18
+ dp = tmp
19
+ #print(dp) # <-- uncomment this line to get a sense of dp from the print output
20
+ # try n = 6, k = 4; your answer should be 49.
21
+ return dp [k ]
0 commit comments