重复给定数组的错位计数
给定一个包含N个数字 ( N ≤ 20 ) 的数组arr[] ,任务是找到数组中可以重复数组元素的Derangements的数量。
A derangement is a permutation of N elements, such that no element appears in its original position. For example, a derangement of {0, 1, 2, 3} is {2, 3, 1, 0}.
例子:
Input: arr[] = {0, 0, 1}
Output: 0
Explanation: All permutations of the array are – {0, 0, 1}, {0, 1, 0} and{1, 0, 0}.
In each permutation, there is atleast one number which is placed in the same position as in the input array.
Hence the answer is 0.
Input: arr[] = {1, 1, 0, 0}
Output: 1
Explanation: The only derangement is {0, 0, 1, 1}
Input: arr[] = {1, 2, 2, 3, 3}
Output: 4
Explanation: The derangements are {2, 3, 3, 1, 2}, {2, 3, 3, 2, 1}, {3, 3, 1, 2, 2} and {3, 1, 3, 2, 2}
朴素方法:解决此问题的最简单方法是生成所有可能的排列,并且对于每个排列,检查是否所有元素都未放置在其原始位置。如果发现为真,则增加计数。最后,打印计数。
时间复杂度: O(N! * N)
辅助空间: O(N)
高效方法:上述方法也可以使用动态编程和位掩码进行优化,因为它具有重叠的子问题和最优的子结构。解决这个问题的想法是基于以下观察:
- For each index of Arr[] the idea is to choose a not selected array element of Arr[] and using bitmasking to keep track of the already selected elements of Arr[]. The selected element must also be not equal to the current element to ensure derangement.
- dp(i, mask) stores the result from the ‘i’th position till the end, with bitmask ‘mask’ denoting the already selected elements of array Arr[] till the ‘i-1’th position.
- Since the current position can be determined by the count of set bits of mask, reduce dp(i, mask) to dp(mask).
- Then the transition from one state to another state can be defined as:
- For all j in the range [0, N – 1]:
- If the jth bit of mask is not set and if A[i] != A[j], then, dp(i, mask) += dp(i + 1, mask|(1<
.
- If the jth bit of mask is not set and if A[i] != A[j], then, dp(i, mask) += dp(i + 1, mask|(1<
- For all j in the range [0, N – 1]:
请按照以下步骤解决问题:
- 定义一个大小为 (1 << N) 的dp数组并将其初始化为 -1 以存储所有 dp 状态。
- 定义一个递归函数说countDerangements(i, mask)来计算错位的数量
- 基本情况,如果i等于N ,则构建了有效的紊乱。
- 如果dp[mask]不等于 -1,即已经访问过,则返回dp[mask]。
- 使用变量j在范围[0, N-1]上进行迭代,并且在每次迭代中,如果未设置掩码中的第 j位并且如果A[i] != A[j] ,则
- 将dp[mask]更新为dp[mask] = dp[mask] + countDerangements (i+1, mask | (<< j)) 。
- 最后,返回 dp[mask]。
- 如果任何数字重复多次,则返回的答案必须除以该数字的频率,因为在不同位置交换相同的数字将导致相同的混乱。
- 因此,检查所有数字的频率,如果它大于 1,则将答案除以数字的频率。
- 这将是最终的答案。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Declaring a dp array
long long dp[1 << 20];
// Function to return
// the factorial of a number
long long factorial(int n)
{
long long fact = 1;
for (int i = 2; i <= n; ++i) {
fact *= i;
}
return fact;
}
// Function to count the
// Number of derangements
long long countDerangements(int i, int mask,
int n, int A[])
{
// If all the numbers are placed,
// then return 1.
if (mask == (1 << n) - 1) {
return 1;
}
// If the state has already been computed,
// then return it
if (dp[mask] != -1) {
return dp[mask];
}
dp[mask] = 0;
// Check for all possible numbers
// that can be placed in
// the current position 'i'.
for (int j = 0; j < n; ++j) {
// If the current element arr[j]
// Is not yet selected
//(bit 'j' is unset in mask),
// And if arr[i]!= arr[j]
//(to ensure derangement).
if (!(mask & (1 << j))
and (A[i] != A[j])) {
// Set the bit 'j' in mask and
// Call the function
// For index 'i + 1'.
dp[mask] += countDerangements(
i + 1, mask | (1 << j), n, A);
}
}
// Return dp[mask]
return dp[mask];
}
// Utility Function to count
// The number of derangements
long long UtilCountDerangements(int A[],
int N)
{
// Initializing the dp array with -1.
memset(dp, -1, sizeof dp);
// HashMap to store the frequency
// of each number.
map frequencyMap;
for (int i = 0; i < N; ++i) {
++frequencyMap[A[i]];
}
// Function call and storing
// The return value in 'ans'.
long long ans
= countDerangements(0, 0, N, A);
// Iterating through the HashMap
for (auto itr : frequencyMap) {
// Frequency of current number
int times = itr.second;
// If it occurs more than 1 time,
// divide the answer by its frequency.
if (times > 1) {
ans /= factorial(times);
}
}
return ans;
}
// Driver code
int main()
{
// Input array
int arr[] = { 1, 2, 2, 3, 3 };
// Size of array
int N = sizeof(arr) / sizeof(arr[0]);
cout << UtilCountDerangements(arr, N);
return 0;
}
Python3
# Python program for the above approach
# Declaring a dp array
dp = [-1]*(1 << 20)
# Function to return
# the factorial of a number
def factorial(n):
fact = 1
for i in range(2,n+1):
fact *= i
return fact
# Function to count the
# Number of derangements
def countDerangements(i,mask,n, A):
# If all the numbers are placed,
# then return 1.
if (mask == (1 << n) - 1):
return 1
# If the state has already been computed,
# then return it
if (dp[mask] != -1):
return dp[mask]
dp[mask] = 0
# Check for all possible numbers
# that can be placed in
# the current position 'i'.
for j in range(n):
# If the current element arr[j]
# Is not yet selected
#(bit 'j' is unset in mask),
# And if arr[i]!= arr[j]
#(to ensure derangement).
if (mask & (1 << j) == 0 and (A[i] != A[j])):
# Set the bit 'j' in mask and
# Call the function
# For index 'i + 1'.
dp[mask] += countDerangements(i + 1, mask | (1 << j), n, A)
# Return dp[mask]
return dp[mask]
# Utility Function to count
# The number of derangements
def UtilCountDerangements(A,N):
# HashMap to store the frequency
# of each number.
frequencyMap = {}
for i in range(N):
if A[i] in frequencyMap:
frequencyMap[A[i]] = frequencyMap[A[i]]+1
else:
frequencyMap[A[i]] = 1
# Function call and storing
# The return value in 'ans'.
ans = countDerangements(0, 0, N, A)
# Iterating through the HashMap
for key,value in frequencyMap.items():
# Frequency of current number
times = value
# If it occurs more than 1 time,
# divide the answer by its frequency.
if (times > 1):
ans = ans // factorial(times)
return ans
# Driver code
# Input array
arr = [ 1, 2, 2, 3, 3 ]
# Size of array
N = len(arr)
print(UtilCountDerangements(arr, N))
# This code is contributed by shinjanpatra.
C#
// C# program of the above approach
using System;
using System.Collections.Generic;
class GFG
{
// Declaring a dp array
static int[] dp = new int[1 << 20];
// Function to return
// the factorial of a number
static int factorial(int n)
{
int fact = 1;
for (int i = 2; i <= n; ++i) {
fact *= i;
}
return fact;
}
// Function to count the
// Number of derangements
static int countDerangements(int i, int mask,
int n, int[] A)
{
// If all the numbers are placed,
// then return 1.
if (mask == (1 << n) - 1) {
return 1;
}
// If the state has already been computed,
// then return it
if (dp[mask] != -1) {
return dp[mask];
}
dp[mask] = 0;
// Check for all possible numbers
// that can be placed in
// the current position 'i'.
for (int j = 0; j < n; ++j) {
// If the current element arr[j]
// Is not yet selected
//(bit 'j' is unset in mask),
// And if arr[i]!= arr[j]
//(to ensure derangement).
if ((mask & (1 << j)) == 0
&& (A[i] != A[j])) {
// Set the bit 'j' in mask and
// Call the function
// For index 'i + 1'.
dp[mask] += countDerangements(
i + 1, mask | (1 << j), n, A);
}
}
// Return dp[mask]
return dp[mask];
}
// Utility Function to count
// The number of derangements
static int UtilCountDerangements(int[] A,
int N)
{
// Initializing the dp array with -1.
for(int i = 0;i<(1 << 20); i++)
{
dp[i]=-1;
}
// HashMap to store the frequency
// of each number.
Dictionary frequencyMap = new Dictionary();
for (int i = 0; i < N; i++) {
if(frequencyMap.ContainsKey(A[i])){
frequencyMap[A[i]] = frequencyMap[A[i]] + 1;
}else{
frequencyMap.Add(A[i], 1);
}
}
// Function call and storing
// The return value in 'ans'.
int ans
= countDerangements(0, 0, N, A);
// Iterating through the HashMap
foreach (KeyValuePair itr in frequencyMap)
{
// Frequency of current number
int times = itr.Value;
// If it occurs more than 1 time,
// divide the answer by its frequency.
if (times > 1) {
ans /= factorial(times);
}
}
return ans;
}
// Driver Code
public static void Main()
{
// Input array
int[] arr = { 1, 2, 2, 3, 3 };
// Size of array
int N = arr.Length;
Console.Write( UtilCountDerangements(arr, N));
}
}
// This code is contributed by sanjoy_62.
Javascript
4
时间复杂度: O(N * 2 N )
辅助空间: O( 2N )