📜  形成n / 2对以使对的差异最小的方式

📅  最后修改于: 2021-06-25 15:38:16             🧑  作者: Mango

给定N个整数的数组arr ,任务是将数组的元素拆分为N / 2对(每对具有2个元素),以使任何一对中的两个元素之间的绝对差值尽可能小。
注意: N将始终为偶数。

例子:

方法:此问题涉及计数的基本原理以及对排列和组合的一些基本理解。

在继续之前,让我们计算一下数组的方法数量= [3,3]
答案= 1,因为只能有1种组合。
现在,让我们将数组修改为[3,3,3,3]。以上示例中讨论的方法是:

进一步将数组修改为[3、3、3、3、3、3]

在这里,我们通过简单的观察获得广义的结果。如果数组中有K个元素具有相同的值,而K为偶数,则在它们之间形成对的方式的数目为:

我们可以如下计算该结果。令Ways []为数组,使ways [i]存储大小为’i’的Ways数量。

现在,计数不必总是保持偶数。因此,如果需要为通用数组解决此问题,我们需要做两件事。

  1. 以升序对数组进行排序。
  2. 分析具有相同值的每个组的计数。

让我们的数组= [2,3,3,3,3,4,4,4,4,4,4] 。该数组已排序。

  • 考虑具有值4的元素。由于有5个元素,所以4个元素将以ways [4]的方式相互配对。剩下的元素可以通过5种方式选择。剩余的元素将必须与值3的元素配对。由于存在4个具有值3的元素,因此以4种方式发生。因此,将保留值3的一个元素与4的元素进行配对。因此3个元素与值3保留下来。 2将以Ways [2]的方式彼此配对,而1将以1的方式与值为2的元素配对。同样,将通过3种方式选择lone元素。
  • 因此,从第1点开始,方法的数量将是:

下面是上述方法的实现:

C++
// C++ implementation of the above approach
#include 
  
#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 count;
    for (int i = 0; i < n; i++)
        count[arr[i]]++;
  
    vector > count_vector;
    map::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