通过对 K 进行模运算,找到 K 以将给定的 Array 转换为排列
给定一个包含N个整数的数组arr[] ,任务是找到一个值K ,使得运算arr[i] = arr[i] % K (0 ≤ i ≤ N-1) 使数组成为一个排列。如果不存在这样的K ,则打印 -1。
A sequence of N integers is called permutation if it contains all integers from 1 to N exactly once.
例子:
Input: N = 3, arr[ ] = {2, 7, 1}
Output: 4
Explanation: [2%4, 7%4, 1%4] = [2, 3, 1] which is a permutation of N = 3.
Input: N = 5, arr[ ] = {18, 81, 29, 36, 11}
Output: 8
Explanation: [18%8, 81%8, 29%8, 36%8, 11%8] = [2, 1, 5, 4, 3] which is a permutation of N = 5.
Input: N = 2, arr[ ] = {2, 2}
Output: -1
方法:给定的问题可以在以下观察的帮助下解决:
If the given arr[] has at least one repeated element, it can never become a permutation. So, all arr[i] must be unique in arr[]. If not, then print -1.
If there exists such K. So, we express each arr[i] in terms of K as given:
- A1 = Q1*K + R1
A2 = Q2*K + R2
A3 = Q3*K + R3
. . . . . .
AN = QN*K + RN - To be a valid K, (R1, R2, R3 …. RN) must be a permutation from 1 to N.
- Hence, Σ arr[i] = (Σ Qi) *K + (Σ Ri).
- We know (Σ Ri) = (N*(N+1))/2 = Sr (Say).
- let S = (Q’) *K +Sr, where Q’ = (Σ Qi).
- let Srem = (Q’) *K = S – Sr = (sum of all array elements) – (N*(N+1))/2.
- It is evident that K must a divisor of Srem.
请按照以下步骤解决问题:
- 检查如果arr[]已经是一个排列,那么可能的答案就是(N+1) 。
- 否则,求所有数组元素的总和。
- 找到S rem的所有除数并检查哪些除数满足在应用给定的模运算时进行数组排列的条件。
下面是上述方法的实现。
C++
// C++ code to implement above approach
#include
using namespace std;
// Function to check is given set a
// permutation
bool is_given_set_permutation(set&
hash,
int N)
{
int last_element = *hash.rbegin();
if (hash.size() == N
&& last_element == N) {
return true;
}
return false;
}
// Function to find the divisors
vector findDivisors(int n)
{
// Note that this loop runs till
// square root
vector divisors;
for (int i = 1; i <= sqrt(n); i++) {
if (n % i == 0) {
// If divisors are equal,
// push only one
if (n / i == i)
divisors.push_back(i);
// Otherwise push both
else {
divisors.push_back(i);
divisors.push_back(n / i);
}
}
}
return divisors;
}
// Function returns if the current divisor
// is the required answer
bool is_current_divisor_answer(int arr[],
int N, int div)
{
set hash;
for (int i{ 0 }; i < N; i++) {
hash.insert(arr[i] % div);
}
return is_given_set_permutation(hash, N);
}
// Function to the number d which on applying
// arr[i]%d to each element makes the array
// a permutation
int number_to_make_permutation(int arr[], int N)
{
// Set to store elements of arr[]
set hash;
for (int i{ 0 }; i < N; i++) {
hash.insert(arr[i]);
}
if (hash.size() != N) {
// When hash size !=N, there are
// repeating elements in arr[].
// So it can never be a permutation
return -1;
}
if (is_given_set_permutation(hash, N)) {
// Given arr[] is already a
// permutation
return (N + 1);
}
int total_sum{ 0 };
// Loop to find the sum of the array
for (int i{ 0 }; i < N; i++) {
total_sum += arr[i];
}
int sum_of_permutation
= (N * (N + 1)) / 2;
int remaining_sum = total_sum - sum_of_permutation;
vector divisors = findDivisors(
remaining_sum);
// Loop to check if any divisor
// satisfies the condition
for (int i{ 0 }; i < divisors.size();
i++) {
// A divisor <= N can
// never be an answer
if (divisors[i] <= N)
continue;
if (is_current_divisor_answer(arr, N,
divisors[i])) {
return divisors[i];
}
}
return -1;
}
// Driver code
int main()
{
int arr[] = { 18, 81, 29, 36, 11 };
int N = sizeof(arr) / sizeof(int);
// Function call
cout << number_to_make_permutation(arr, N);
return 0;
}
Python3
# Python3 code to implement above approach
import math
# Function to check is given set a
# permutation
def is_given_set_permutation(hash, N):
last_element = list(hash)[len(hash) - 1]
if (len(hash) == N and last_element == N):
return True
return False
# Function to find the divisors
def findDivisors(n):
# Note that this loop runs till
# square root
divisors = []
for i in range(1, int(math.sqrt(n)) + 1):
if (n % i == 0):
# If divisors are equal,
# push only one
if (n // i == i):
divisors.append(i)
# Otherwise push both
else:
divisors.append(i)
divisors.append(n // i)
return divisors
# Function returns if the current divisor
# is the required answer
def is_current_divisor_answer(arr, N, div):
hash = set()
for i in range(0, N):
hash.add(arr[i] % div)
return is_given_set_permutation(hash, N)
# Function to the number d which on applying
# arr[i]%d to each element makes the array
# a permutation
def number_to_make_permutation(arr, N):
# Set to store elements of arr[]
hash = set()
for i in range(0, N):
hash.add(arr[i])
if (len(hash) != N):
# When hash size !=N, there are
# repeating elements in arr[].
# So it can never be a permutation
return -1
if (is_given_set_permutation(hash, N)):
# Given arr[] is already a
# permutation
return (N + 1)
total_sum = 0
# Loop to find the sum of the array
for i in range(0, N):
total_sum += arr[i]
sum_of_permutation = (N * (N + 1)) // 2
remaining_sum = total_sum - sum_of_permutation
divisors = findDivisors(remaining_sum)
# Loop to check if any divisor
# satisfies the condition
for i in range(0, len(divisors)):
# A divisor <= N can
# never be an answer
if (divisors[i] <= N):
continue
if (is_current_divisor_answer(arr, N, divisors[i])):
return divisors[i]
return -1
# Driver code
if __name__ == "__main__":
arr = [18, 81, 29, 36, 11]
N = len(arr)
# Function call
print(number_to_make_permutation(arr, N))
# This code is contributed by rakeshsahni
8
时间复杂度: O(N * F),其中 F 是除数的最大数量。
辅助空间: O(N)