Ways to form n/2 pairs such that difference of pairs is minimum
Given an array arr of N integers, the task is to split the elements of the array into N/2 pairs (each pair having 2 elements) such that the absolute difference between two elements of any pair is as minimum as possible. Note: N will always be even. Examples:
Input: arr[] = {1, 7, 3, 8} Output: 1 There is only one way to form pairs with minimum difference, (7, 8) and (1, 3). Input: arr[] = {1, 1, 1, 1, 2, 2, 2, 2} Output: 9 Here all elements with value 2 will pair amongst themselves (3 ways possible) and all elements with value 1 will make pairs between them (3 ways possible) Therefore, number of ways = 3 * 3 = 9 Input: arr[] = {2, 3, 2, 2} Output: 3
Approach: This problem involves the fundamental principle of counting and some basic understanding of permutations and combinations. Before going any further, let’s count the number of ways for the array = [3, 3] Answer = 1, since only 1 combination is possible. Now, lets modify the array to [3, 3, 3, 3]. The ways for this as discussed in the above examples are:
(1, 2), (3, 4) (1, 3), (2, 4) (1, 4), (2, 3) Answer = 3 ways.
Further modifying the array to [3, 3, 3, 3, 3, 3]
(1, 2), (3, 4), (5, 6) (1, 2), (3, 5), (4, 6) (1, 2), (3, 6), (4, 5) (1, 3), (2, 4), (5, 6) (1, 3), (2, 5), (4, 6) (1, 3), (2, 6), (4, 5) (1, 4), (2, 3), (5, 6) (1, 4), (2, 5), (3, 6) (1, 4), (2, 6), (3, 5) (1, 5), (2, 3), (4, 6) (1, 5), (2, 4), (3, 6) (1, 5), (2, 6), (3, 4) (1, 6), (2, 3), (4, 5) (1, 6), (2, 4), (3, 5) (1, 6), (2, 5), (3, 4) Answer = 15 ways.
Here we obtain a generalized result by simple observation. If there are K elements in the array that have the same value and K is even, then the number of ways to form pairs amongst them:
For size 2, count = 1 (1) For size 4, count = 3 (1 * 3) For size 6, count = 15 (1 * 3 * 5) And so on. Hence, number of ways to form pairs for size K where K is even = 1 * 3 * 5 * …. * (K-1)
We can precompute this result as follows. Let ways[] be the array such that ways[i] stores the number of ways for size ‘i’.
ways[2] = 1; for(i = 4; i < 1e5 + 1; i += 2) ways[i] = ways[i – 2] * (i – 1); For example, we consider array [3, 3, 3, 3, 3] To compute the number of ways, we fix the first element with any of the remaining 5. So we form one pair. Now 4 elements are left that can be paired in ways[4] ways. So number of ways would be 5 * ways[4].
Now, it may not be necessary that counts may always be even in number. Therefore, if need to solve this for a general array, we need to do two things.
- Sort the array in ascending order.
- Analyze the count of each group having the same value.
Let our array = [2, 3, 3, 3, 3, 4, 4, 4, 4, 4]. This array is sorted.
- Considering element with value 4. Since there are 5 elements, 4 elements will pair amongst themselves in ways[4] ways. The left out element can be chosen in 5 ways. The element left will have to pair with an element with value 3. This happens in 4 ways since there are 4 elements with value 3. Therefore, one element of value 3 will be reserved to pair with an element of 4. So 3 elements with value 3 remain. 2 will pair amongst themselves in ways[2] ways and one 1 will pair with the element with value 2 in 1 way. Again, the lone element will be selected in 3 ways.
- Therefore from point 1, number of ways will be :
Below is the implementation of the above approach:
C++
// C++ implementation of the above approach #include <bits/stdc++.h> #define mp make_pair #define pb push_back #define S second #define ll long long using namespace std; // Using mod because the number // of ways might be very large const int mod = 1000000007; const int MAX = 100000; // ways is serving the same // purpose as discussed ll ways[MAX + 1]; void preCompute() { // pairing up zero people // requires one way. ways[0] = 1LL; ways[2] = 1LL; for ( int i = 4; i <= MAX; i += 2) { ways[i] = (1LL * (i - 1) * ways[i - 2]) % mod; } } void countWays( int * arr, int n) { // map count stores count of s. map< int , int > count; for ( int i = 0; i < n; i++) count[arr[i]]++; vector<pair< int , int > > count_vector; map< int , int >::iterator it; for (it = count.begin(); it != count.end(); it++) { count_vector.pb(mp(it->first, it->second)); } // vector count_vector stores a // pair < value, count of value> // sort according to value sort(count_vector.begin(), count_vector.end()); ll ans = 1; // Iterating backwards. for ( int i = count_vector.size() - 1; i > 0; i--) { int current_count = count_vector[i].S; int prev_count = count_vector[i - 1].S; // Checking if current count is odd. if (current_count & 1) { // if current count = 5, multiply ans by ways[4]. ans = (ans * ways[current_count - 1]) % mod; // left out person will be selected // in current_count ways ans = (ans * current_count) % mod; // left out person will pair with previous // person in previous_count ways ans = (ans * prev_count) % mod; /* if previous count is odd, * then multiply answer by ways[prev_count-1]. * since one has already been reserved, * remaining will be even. * reduce prev_count = 0, since we don't need it now.*/ if (prev_count & 1) { ans = (ans * ways[prev_count - 1]) % mod; count_vector[i - 1].S = 0; } else { /* if prev count is even, one will be reserved, * therefore decrement by 1. * In the next iteration, prev_count will become odd * and it will be handled in the same way.*/ count_vector[i - 1].S--; } } else { /* if current count is even, * then simply multiply ways[current_count] * to answer.*/ ans = (ans * ways[current_count]) % mod; } } /* multiply answer by ways[first__count] since that is left out, after iterating the array.*/ ans = (ans * ways[count_vector[0].S]) % mod; cout << ans << "\n" ; } // Driver code int main() { preCompute(); int arr[] = { 2, 3, 3, 3, 3, 4, 4, 4, 4, 4 }; int n = sizeof (arr) / sizeof (arr[0]); countWays(arr, n); return 0; } |
Python3
# Python3 implementation of the # above approach from collections import defaultdict # Using mod because the number # of ways might be very large mod = 1000000007 MAX = 100000 # ways is serving the same # purpose as discussed ways = [ None ] * ( MAX + 1 ) def preCompute(): # pairing up zero people # requires one way. ways[ 0 ] = 1 ways[ 2 ] = 1 for i in range ( 4 , MAX + 1 , 2 ): ways[i] = (( 1 * (i - 1 ) * ways[i - 2 ]) % mod) def countWays(arr, n): # map count stores count of s. count = defaultdict( lambda : 0 ) for i in range ( 0 , n): count[arr[i]] + = 1 count_vector = [] for key in count: count_vector.append([key, count[key]]) # vector count_vector stores a # pair < value, count of value> # sort according to value count_vector.sort() ans = 1 # Iterating backwards. for i in range ( len (count_vector) - 1 , - 1 , - 1 ): current_count = count_vector[i][ 1 ] prev_count = count_vector[i - 1 ][ 1 ] # Checking if current count is odd. if current_count & 1 : # if current count = 5, multiply # ans by ways[4]. ans = (ans * ways[current_count - 1 ]) % mod # left out person will be selected # in current_count ways ans = (ans * current_count) % mod # left out person will pair with previous # person in previous_count ways ans = (ans * prev_count) % mod # if previous count is odd, # then multiply answer by ways[prev_count-1]. # since one has already been reserved, # remaining will be even. # reduce prev_count = 0, since we # don't need it now. if prev_count & 1 : ans = (ans * ways[prev_count - 1 ]) % mod count_vector[i - 1 ][ 1 ] = 0 else : # if prev count is even, one will be # reserved, therefore decrement by 1. # In the next iteration, prev_count # will become odd and it will be # handled in the same way. count_vector[i - 1 ][ 1 ] - = 1 else : # if current count is even, then simply # multiply ways[current_count] to answer. ans = (ans * ways[current_count]) % mod # multiply answer by ways[first__count] since # that is left out, after iterating the array. ans = (ans * ways[count_vector[ 0 ][ 1 ]]) % mod print (ans) # Driver code if __name__ = = "__main__" : preCompute() arr = [ 2 , 3 , 3 , 3 , 3 , 4 , 4 , 4 , 4 , 4 ] n = len (arr) countWays(arr, n) # This code is contributed by Rituraj Jain |
180
Time Complexity: O(nlogn)
Auxiliary Space: O(MAX + n)