You are given an integer n
and a 2D array requirements
, where requirements[i] = [endi, cnti]
represents the end index and the inversion count of each requirement.
A pair of indices (i, j)
from an integer array nums
is called an inversion if:
i < j
and nums[i] > nums[j]
Return the number of permutations perm
of [0, 1, 2, ..., n - 1]
such that for all requirements[i]
, perm[0..endi]
has exactly cnti
inversions.
Since the answer may be very large, return it modulo 109 + 7
.
Example 1:
Input: n = 3, requirements = [[2,2],[0,0]]
Output: 2
Explanation:
The two permutations are:
[2, 0, 1]
[2, 0, 1]
has inversions (0, 1)
and (0, 2)
.[2]
has 0 inversions.[1, 2, 0]
[1, 2, 0]
has inversions (0, 2)
and (1, 2)
.[1]
has 0 inversions.Example 2:
Input: n = 3, requirements = [[2,2],[1,1],[0,0]]
Output: 1
Explanation:
The only satisfying permutation is [2, 0, 1]
:
[2, 0, 1]
has inversions (0, 1)
and (0, 2)
.[2, 0]
has an inversion (0, 1)
.[2]
has 0 inversions.Example 3:
Input: n = 2, requirements = [[0,0],[1,0]]
Output: 1
Explanation:
The only satisfying permutation is [0, 1]
:
[0]
has 0 inversions.[0, 1]
has an inversion (0, 1)
.Constraints:
2 <= n <= 300
1 <= requirements.length <= n
requirements[i] = [endi, cnti]
0 <= endi <= n - 1
0 <= cnti <= 400
i
such that endi == n - 1
.endi
are unique.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force way to count inversions is to check every possible pair of items in the list. We compare each item to all the items that come after it to see if they are out of order. If they are, we count them.
Here's how the algorithm would work step-by-step:
def count_inversions_brute_force(number_list):
inversion_count = 0
list_length = len(number_list)
for first_index in range(list_length):
# Iterate through the list.
for second_index in range(first_index + 1, list_length):
# Compare the current element to all subsequent elements.
if number_list[first_index] > number_list[second_index]:
# If a later element is smaller, it's an inversion.
inversion_count += 1
return inversion_count
To count inversions efficiently, we'll use a divide-and-conquer strategy. We'll break the problem into smaller, easier-to-solve subproblems, and then combine the results in a way that also counts the inversions created during the merging process.
Here's how the algorithm would work step-by-step:
def count_inversions(number_list):
return count_inversions_recursive(number_list, 0, len(number_list) - 1)
def count_inversions_recursive(number_list, start_index, end_index):
inversion_count = 0
if start_index < end_index:
middle_index = (start_index + end_index) // 2
# Recursively count inversions in the left and right subarrays.
inversion_count += count_inversions_recursive(number_list, start_index, middle_index)
inversion_count += count_inversions_recursive(number_list, middle_index + 1, end_index)
# Merge the two sorted subarrays and count inversions during the merge.
inversion_count += merge_and_count(number_list, start_index, middle_index, end_index)
return inversion_count
def merge_and_count(number_list, start_index, middle_index, end_index):
left_subarray = number_list[start_index:middle_index + 1]
right_subarray = number_list[middle_index + 1:end_index + 1]
left_index = 0
right_index = 0
merged_index = start_index
inversion_count = 0
# Iterate until one of the subarrays is exhausted.
while left_index < len(left_subarray) and right_index < len(right_subarray):
if left_subarray[left_index] <= right_subarray[right_index]:
number_list[merged_index] = left_subarray[left_index]
left_index += 1
else:
number_list[merged_index] = right_subarray[right_index]
right_index += 1
# Count inversions.
# Remaining elements in left are greater than current right.
inversion_count += (len(left_subarray) - left_index)
merged_index += 1
# Copy any remaining elements from the left subarray.
while left_index < len(left_subarray):
number_list[merged_index] = left_subarray[left_index]
left_index += 1
merged_index += 1
# Copy any remaining elements from the right subarray.
while right_index < len(right_subarray):
number_list[merged_index] = right_subarray[right_index]
right_index += 1
merged_index += 1
return inversion_count
Case | How to Handle |
---|---|
Null or empty input array | Return 0 since an empty array has no inversions. |
Array with one element | Return 0 since a single element cannot form an inversion. |
Array with two elements, sorted | Return 0 as there is no inversion. |
Array with two elements, unsorted | Return 1, representing the single inversion. |
Array with all elements identical | Return 0 since there are no inversions. |
Array with already reverse sorted elements | Expect a high number of inversions equal to n*(n-1)/2. |
Large input array exceeding memory limitations during merge sort | Consider using an in-place merge sort (though less efficient) or reporting an error if memory limits are hit. |
Integer overflow if the number of inversions is very large | Use a 64-bit integer type (long in Java, long long in C++) to store the inversion count to prevent overflow. |