📜  到达置换数组的最小交换,最多允许剩余2个位置交换

📅  最后修改于: 2021-04-24 20:46:03             🧑  作者: Mango

给定一个长度为N的前N个自然数的置换数组,我们需要说出前N个自然数的排序数组中达到给定置换数组所需的最小交换次数,在该置换数组中,一个数字最多可以交换2个位置它。如果无法通过上述交换条件到达排列的数组,则无法打印。
例子:

Input : arr = [1, 2, 5, 3, 4]
Output : 2
We can reach to above-permuted array 
in total 2 swaps as shown below,
[1, 2, 3, 4, 5] -> [1, 2, 3, 5, 4] -> 
[1, 2, 5, 3, 4]

Input : arr[] = [5, 1, 2, 3, 4]
Output : Not Possible
It is not possible to reach above array 
just by swapping numbers 2 positions left
to it.

我们可以使用反演来解决这个问题。正如我们所看到的,如果一个数字位于一个比其实际位置多2个位置的位置,那么仅通过与左边2个位置的元素交换并且如果所有元素都满足此属性,就不可能到达该位置。 <= 2个比右边小的元素),则答案将只是数组中的求反总数,因为需要大量交换才能将数组转换为置换数组。
我们可以使用此处说明的合并排序技术找到N log N时间的求逆数,因此解决方案的总时间复杂度仅为O(N log N)。

C++
// C++ program to find minimum number of swaps
// to reach a permutation wiht at most 2 left
// swaps allowed for every element
#include 
using namespace std;
  
/* This funt merges two sorted arrays and returns inversion
   count in the arrays.*/
int merge(int arr[], int temp[], int left, int mid, int right)
{
    int inv_count = 0;
  
    int i = left; /* i is index for left subarray*/
    int j = mid;  /* j is index for right subarray*/
    int k = left; /* k is index for resultant merged subarray*/
    while ((i <= mid - 1) && (j <= right))
    {
        if (arr[i] <= arr[j])
            temp[k++] = arr[i++];
        else
        {
            temp[k++] = arr[j++];
            inv_count = inv_count + (mid - i);
        }
    }
  
    /* Copy the remaining elements of left subarray
    (if there are any) to temp*/
    while (i <= mid - 1)
        temp[k++] = arr[i++];
  
    /* Copy the remaining elements of right subarray
    (if there are any) to temp*/
    while (j <= right)
       temp[k++] = arr[j++];
  
    /*Copy back the merged elements to original array*/
    for (i = left; i <= right; i++)
        arr[i] = temp[i];
  
    return inv_count;
}
  
/* An auxiliary recursive function that sorts the
   input array and returns the number of inversions
   in the array. */
int _mergeSort(int arr[], int temp[], int left, int right)
{
    int mid, inv_count = 0;
    if (right > left)
    {
        /* Divide the array into two parts and
           call _mergeSortAndCountInv() for each
           of the parts */
        mid = (right + left)/2;
  
        /* Inversion count will be sum of inversions
          in left-part, right-part and number of inversions
          in merging */
        inv_count  = _mergeSort(arr, temp, left, mid);
        inv_count += _mergeSort(arr, temp, mid+1, right);
  
        /*Merge the two parts*/
        inv_count += merge(arr, temp, left, mid+1, right);
    }
    return inv_count;
}
  
  
/* This function sorts the input array and returns the
   number of inversions in the array */
int mergeSort(int arr[], int array_size)
{
    int *temp = (int *)malloc(sizeof(int)*array_size);
    return _mergeSort(arr, temp, 0, array_size - 1);
}
  
// method returns minimum number of swaps to reach
// permuted array 'arr'
int minSwapToReachArr(int arr[], int N)
{
    //  loop over all elements to check Invalid
    // permutation condition
    for (int i = 0; i < N; i++)
    {
        /*  if an element is at distance more than 2
            from its actual position then it is not
            possible to reach permuted array just
            by swapping with 2 positions left elements
            so returning -1   */
        if ((arr[i] - 1) - i > 2)
            return -1;
    }
  
    /*  If permuted array is not Invalid, then number
        of Inversion in array will be our final answer */
    int numOfInversion = mergeSort(arr, N);
    return numOfInversion;
}
  
//  Driver code to test above methods
int main()
{
    //  change below example
    int arr[] = {1, 2, 5, 3, 4};
    int N = sizeof(arr) / sizeof(int);
    int res = minSwapToReachArr(arr, N);
    if (res == -1)
        cout << "Not Possible\n";
    else
        cout << res << endl;
    return 0;
}


Java
// Java program to find minimum 
// number of swaps to reach a 
// permutation wiht at most 2 left 
// swaps allowed for every element 
class GFG
{
  
    /* This funt merges two sorted
    arrays and returns inversion 
    count in the arrays.*/
    static int merge(int arr[], int temp[], int left,
                                int mid, int right)
    {
        int inv_count = 0;
  
        int i = left;
          
        /* i is index for left subarray*/
        int j = mid;
          
        /* j is index for right subarray*/
        int k = left;
          
        /* k is index for resultant merged subarray*/
        while ((i <= mid - 1) && (j <= right)) 
        {
            if (arr[i] <= arr[j])
            {
                temp[k++] = arr[i++];
            } 
            else
            {
                temp[k++] = arr[j++];
                inv_count = inv_count + (mid - i);
            }
        }
  
        /* Copy the remaining elements 
        of left subarray (if there
         are any) to temp*/
        while (i <= mid - 1) 
        {
            temp[k++] = arr[i++];
        }
  
        /* Copy the remaining elements 
        of right subarray (if there
        are any) to temp*/
        while (j <= right)
        {
            temp[k++] = arr[j++];
        }
  
        /* Copy back the merged elements
        to original array*/
        for (i = left; i <= right; i++) 
        {
            arr[i] = temp[i];
        }
  
        return inv_count;
    }
  
    /* An auxiliary recursive function 
     that sorts the input array and
     returns the number of inversions 
    in the array. */
    static int _mergeSort(int arr[], int temp[], 
                            int left, int right)
    {
        int mid, inv_count = 0;
        if (right > left) 
        {
            /* Divide the array into two parts and 
            call _mergeSortAndCountInv() for each 
            of the parts */
            mid = (right + left) / 2;
  
            /* Inversion count will be sum of inversions 
            in left-part, right-part and number of inversions 
            in merging */
            inv_count = _mergeSort(arr, temp, left, mid);
            inv_count += _mergeSort(arr, temp, mid + 1, right);
  
            /* Merge the two parts*/
            inv_count += merge(arr, temp, left, mid + 1, right);
        }
        return inv_count;
    }
  
  
    /* This function sorts the input array and returns the 
    number of inversions in the array */
    static int mergeSort(int arr[], int array_size)
    {
        int[] temp = new int[array_size];
        return _mergeSort(arr, temp, 0, array_size - 1);
    }
  
    // method returns minimum number of  
    // swaps to reach permuted array 'arr' 
    static int minSwapToReachArr(int arr[], int N) 
    {
        // loop over all elements to check Invalid 
        // permutation condition 
        for (int i = 0; i < N; i++)
        {
            /* if an element is at distance more than 2 
            from its actual position then it is not 
            possible to reach permuted array just 
            by swapping with 2 positions left elements 
            so returning -1 */
            if ((arr[i] - 1) - i > 2)
            {
                return -1;
            }
        }
  
        /* If permuted array is not Invalid, then number 
        of Inversion in array will be our final answer */
        int numOfInversion = mergeSort(arr, N);
        return numOfInversion;
    }
  
    // Driver code 
    public static void main(String[] args) 
    {
          
        // change below example 
        int arr[] = {1, 2, 5, 3, 4};
        int N = arr.length;
        int res = minSwapToReachArr(arr, N);
        System.out.println(res == -1 ? "Not Possible\n" : res);
    }
}
  
// This code contributed by Rajput-Ji


Python3
# Python3 program to find minimum number of
# swaps to reach a permutation wiht at most
# 2 left swaps allowed for every element
  
# This funt merges two sorted arrays and
# returns inversion count in the arrays.
def merge(arr, temp, left, mid, right):
  
    inv_count = 0
  
    i = left # i is index for left subarray
    j = mid # j is index for right subarray
    k = left # k is index for resultant merged subarray
    while (i <= mid - 1) and (j <= right):
      
        if arr[i] <= arr[j]:
            temp[k] = arr[i]
            k, i = k + 1, i + 1
          
        else:
            temp[k] = arr[j]
            k, j = k + 1, j + 1
            inv_count = inv_count + (mid - i)
  
    # Copy the remaining elements of left
    # subarray (if there are any) to temp
    while i <= mid - 1:
        temp[k] = arr[i]
        k, i = k + 1, i + 1
  
    # Copy the remaining elements of right
    # subarray (if there are any) to temp
    while j <= right:
        temp[k] = arr[j]
        k, j = k + 1, j + 1
  
    # Copy back the merged elements to original array
    for i in range(left, right + 1):
        arr[i] = temp[i]
  
    return inv_count
  
# An auxiliary recursive function that
# sorts the input array and returns the
# number of inversions in the array.
def _mergeSort(arr, temp, left, right):
  
    inv_count = 0
    if right > left:
      
        # Divide the array into two parts
        # and call _mergeSortAndCountInv()
        # for each of the parts
        mid = (right + left) // 2
  
        # Inversion count will be sum of
        # inversions in left-part, right-part
        # and number of inversions in merging 
        inv_count = _mergeSort(arr, temp, left, mid)
        inv_count += _mergeSort(arr, temp, mid + 1, right)
  
        # Merge the two parts
        inv_count += merge(arr, temp, left, mid + 1, right)
      
    return inv_count
  
# This function sorts the input array and
# returns the number of inversions in the array 
def mergeSort(arr, array_size):
  
    temp = [None] * array_size
    return _mergeSort(arr, temp, 0, array_size - 1)
  
# method returns minimum number of
# swaps to reach permuted array 'arr'
def minSwapToReachArr(arr, N):
  
    # loop over all elements to check
    # Invalid permutation condition
    for i in range(0, N):
      
        # if an element is at distance more than 2
        # from its actual position then it is not
        # possible to reach permuted array just
        # by swapping with 2 positions left elements
        # so returning -1
        if (arr[i] - 1) - i > 2:
            return -1
      
    # If permuted array is not Invalid, then number
    # of Inversion in array will be our final answer
    numOfInversion = mergeSort(arr, N)
    return numOfInversion
  
# Driver code to test above methods
if __name__ == "__main__":
  
    # change below example
    arr = [1, 2, 5, 3, 4]
    N = len(arr)
    res = minSwapToReachArr(arr, N)
    if res == -1:
        print("Not Possible")
    else:
        print(res)
  
# This code is contributed by Rituraj Jain


C#
// C# program to find minimum 
// number of swaps to reach a 
// permutation wiht at most 2 left 
// swaps allowed for every element 
using System;
class GFG
{
  
    /* This funt merges two sorted
    arrays and returns inversion 
    count in the arrays.*/
    static int merge(int []arr, int []temp, 
                     int left, int mid, int right)
    {
        int inv_count = 0;
  
        int i = left;
          
        /* i is index for left subarray*/
        int j = mid;
          
        /* j is index for right subarray*/
        int k = left;
          
        /* k is index for resultant merged subarray*/
        while ((i <= mid - 1) && (j <= right)) 
        {
            if (arr[i] <= arr[j])
            {
                temp[k++] = arr[i++];
            } 
            else
            {
                temp[k++] = arr[j++];
                inv_count = inv_count + (mid - i);
            }
        }
  
        /* Copy the remaining elements 
        of left subarray (if there
        are any) to temp*/
        while (i <= mid - 1) 
        {
            temp[k++] = arr[i++];
        }
  
        /* Copy the remaining elements 
        of right subarray (if there
        are any) to temp*/
        while (j <= right)
        {
            temp[k++] = arr[j++];
        }
  
        /* Copy back the merged elements
        to original array*/
        for (i = left; i <= right; i++) 
        {
            arr[i] = temp[i];
        }
  
        return inv_count;
    }
  
    /* An auxiliary recursive function 
    that sorts the input array and
    returns the number of inversions 
    in the array. */
    static int _mergeSort(int []arr, int []temp, 
                          int left, int right)
    {
        int mid, inv_count = 0;
        if (right > left) 
        {
            /* Divide the array into two parts and 
            call _mergeSortAndCountInv() for each 
            of the parts */
            mid = (right + left) / 2;
  
            /* Inversion count will be sum of inversions 
            in left-part, right-part and number of inversions 
            in merging */
            inv_count = _mergeSort(arr, temp, left, mid);
            inv_count += _mergeSort(arr, temp, mid + 1, right);
  
            /* Merge the two parts*/
            inv_count += merge(arr, temp, left, mid + 1, right);
        }
        return inv_count;
    }
  
    /* This function sorts the input array and returns 
    the number of inversions in the array */
    static int mergeSort(int []arr, int array_size)
    {
        int[] temp = new int[array_size];
        return _mergeSort(arr, temp, 0, array_size - 1);
    }
  
    // method returns minimum number of 
    // swaps to reach permuted array 'arr' 
    static int minSwapToReachArr(int []arr, int N) 
    {
        // loop over all elements to check Invalid 
        // permutation condition 
        for (int i = 0; i < N; i++)
        {
            /* if an element is at distance more than 2 
            from its actual position then it is not 
            possible to reach permuted array just 
            by swapping with 2 positions left elements 
            so returning -1 */
            if ((arr[i] - 1) - i > 2)
            {
                return -1;
            }
        }
  
        /* If permuted array is not Invalid, then number 
        of Inversion in array will be our final answer */
        int numOfInversion = mergeSort(arr, N);
        return numOfInversion;
    }
  
    // Driver code 
    static void Main() 
    {
          
        // change below example 
        int []arr = {1, 2, 5, 3, 4};
        int N = arr.Length;
        int res = minSwapToReachArr(arr, N);
        if(res == -1)
        Console.WriteLine("Not Possible");
        else
        Console.WriteLine(res);
    }
}
  
// This code is contributed by mits


输出:

2