给定一个长度为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