最小化模运算以使给定的 Array 排列为 [1, N]
给定一个大小为N的数组arr[] ,任务是找到使数组成为 [1, N] 范围内数字的排列所需的最小操作次数,其中,在每个操作中,任何索引i处的元素都可以是替换为arr[i]%k (k = 任何大于 0 的值)。如果数组不能成为范围[1, N]中数字的排列,则返回-1 。
例子:
Input: arr [] = {1, 7}, N = 2
Output: 1
Explanation: The only possible sequence of operations which minimizes the no of operations is
Choose i = 1, k = 5. Perform arr[1] = arr[1] % 5 = 2.
Input: arr [] = {1,5,4}, N = 3
Output: -1
Explanation: It is impossible to obtain a permutation of integers from 1 to N.
方法:根据以下观察可以解决问题。
x % y < (x/2) if x ≥ y, and
x % y = x if x < y.
As bigger is x, the longer the range of values that can be obtained after one mod operation.
So try to, assign smaller arr[i] to smaller numbers in the resulting permutation.
Although, if arr[i] satisfies 1 ≤ arr[i] ≤ N, just leave it there and use it in the resulting permutation.
if multiple arr[i] satisfy the same condition and have the same value, just choose one.
Let’s suppose in the optimal solution, l is changed to m and n to l for some n > l > m (l, m, n are values, not indices).
Then keeping l intact and changing n to m uses 1 less operation.
And, if it is possible to change n to l, then it must be possible to change n to m.
按照下面提到的步骤来实施该方法:
- 对数组进行排序。
- 如果1 ≤ arr[i] ≤ N并且它是值为 arr[i] 的元素的第一次出现,则将其保留在那里。
- 否则,令结果排列中当前最少未赋值的值为 x:
- 如果x < arr[i]/2 ,则将当前元素赋值给 x 并将操作数加 1。
- 否则,直接输出-1。
下面是上述方法的实现。
C++
// C++ code to implement above approach
#include
using namespace std;
// Function to find minimum operations
// used to make permutation of 1 to N
void minoperation(vector arr, int N)
{
set st;
vector rem;
// Storing one instance of every element
// from 1 to N
for (int i = 1; i <= N; i++) {
st.insert(i);
}
for (int i = 0; i < N; i++) {
if (st.find(arr[i]) != st.end())
st.erase(arr[i]);
else
rem.push_back(arr[i]);
}
// Sorting in descending order
sort(rem.begin(), rem.end());
reverse(rem.begin(), rem.end());
int pt = 0;
bool flag = false;
for (auto& x : rem) {
auto it = st.end();
it--;
int p = (*it);
if (p > (x - 1) / 2) {
flag = true;
break;
}
st.erase(it);
}
if (flag) {
// Not possible to make permutation.
cout << "-1";
}
else {
// Minimum number of operation required.
cout << rem.size();
}
}
// Driver code
int main()
{
int N = 3;
vector arr = { 1, 5, 4 };
minoperation(arr, N);
return 0;
}
Java
// Java code to implement above approach
import java.util.*;
class GFG{
// Function to find minimum operations
// used to make permutation of 1 to N
static void minoperation(int[] arr, int N)
{
HashSet st = new HashSet();
Vector rem = new Vector();
// Storing one instance of every element
// from 1 to N
for (int i = 1; i <= N; i++) {
st.add(i);
}
for (int i = 0; i < N; i++) {
if (st.contains(arr[i]))
st.remove(arr[i]);
else
rem.add(arr[i]);
}
// Sorting in descending order
Collections.sort(rem,Collections.reverseOrder());
boolean flag = false;
for (int x : rem) {
int it = st.size();
it--;
int p = new ArrayList<>(st).get(it);
if (p > (x - 1) / 2) {
flag = true;
break;
}
st.remove(it);
}
if (flag) {
// Not possible to make permutation.
System.out.print("-1");
}
else {
// Minimum number of operation required.
System.out.print(rem.size());
}
}
// Driver code
public static void main(String[] args)
{
int N = 3;
int[] arr = { 1, 5, 4 };
minoperation(arr, N);
}
}
// This code is contributed by 29AjayKumar
C#
// C# code to implement above approach
using System;
using System.Collections.Generic;
class GFG
{
// Function to find minimum operations
// used to make permutation of 1 to N
static void minoperation(int[] arr, int N)
{
HashSet st = new HashSet();
List rem = new List();
// Storing one instance of every element
// from 1 to N
for (int i = 1; i <= N; i++)
{
st.Add(i);
}
for (int i = 0; i < N; i++)
{
if (st.Contains(arr[i]))
st.Remove(arr[i]);
else
rem.Add(arr[i]);
}
// Sorting in descending order
rem.Sort();
rem.Reverse();
bool flag = false;
foreach (int x in rem)
{
int it = st.Count;
it--;
int p = new List(st)[it];
if (p > (x - 1) / 2)
{
flag = true;
break;
}
st.Remove(it);
}
if (flag)
{
// Not possible to make permutation.
Console.Write("-1");
}
else
{
// Minimum number of operation required.
Console.Write(rem.Count);
}
}
// Driver code
public static void Main()
{
int N = 3;
int[] arr = { 1, 5, 4 };
minoperation(arr, N);
}
}
// This code is contributed by Saurabh jaiswal
Python3
# Python 3 code to implement above approach
# Function to find minimum operations
# used to make permutation of 1 to N
def minoperation(arr, N):
st = set([])
rem = []
# Storing one instance of every element
# from 1 to N
for i in range(1, N + 1):
st.add(i)
for i in range(N):
if (arr[i] in st):
st.remove(arr[i])
else:
rem.append(arr[i])
# Sorting in descending order
rem.sort()
rem.reverse()
pt = 0
flag = False
for x in rem:
it = len(st)
it -= 1
p = list(st)[it]
if (p > (x - 1) / 2):
flag = True
break
st.remove(it)
if (flag):
# Not possible to make permutation.
print("-1")
else:
# Minimum number of operation required.
print(len(rem))
# Driver code
if __name__ == "__main__":
N = 3
arr = [1, 5, 4]
minoperation(arr, N)
# This code is contributed by ukasp.
Javascript
-1
时间复杂度: O(N * logN)
辅助空间: 在)