生成 1 到 N 的排列,每个元素的前缀最小值之和为 Y
给定两个整数N , Y ,生成长度为N的排列,使得该排列的所有前缀最小值之和为Y 。
例子:
Input: N = 5, Y = 10
Output: 5 2 1 4 3
Explanation: Array of prefix minimum for [5, 2, 1, 4, 3] is [5, 2, 1, 1, 1]. Sum of this array of prefix minimum is 10 (= Y).
Input: N = 5, Y = 5
Output: 1 2 3 4 5
Explanation: Array of prefix minimum for [1, 2, 3, 4, 5] is [1, 1, 1, 1, 1]. Sum of this array of prefix minimum is 5 (= Y).
方法:解决此问题的方法基于以下思想:
Suppose the remaining array to be created at some point of time be len and the remaining sum to be rem.
Greedily choose a value for this index by the given method below:
- let’s take Z value at this index, then we should have at least (Z + len – 1) = rem (By taking 1 at remaining indices).
- So, we get Z = (rem + 1 – len). Now, this value might be greater than len but we can’t take it. So, we will choose min(Z, len).
请按照以下步骤解决此问题:
- 现在,已经从上述贪心方法构建了所需排列的前缀最小数组。
- 它也可能有重复。因此,要以相反的顺序删除该数组的迭代,并且每当 arr[i] = arr[i-1] 时,将不存在于任何索引处的最小元素放在第 i个索引处。
- 这样,确保前缀最小值之和应为 Y,并且创建的数组也应为排列。
- 打印最终数组
下面是上述方法的实现:
C++
// C++ program for Generate permutation
// of length N such that sum of all prefix
// minimum of that permutation is Y.
#include
#include
#include
using namespace std;
// Find the value greedily for the
// current index as discussed in approach
int findValue(long long N, long long Y)
{
return min(N, Y + 1 - N);
}
// Function to generate the permutation
void generatePermutation(long long N, long long Y)
{
// Store the prefix minimum array first
// then we will convert it to permutation
vector ans(N);
// If Y should belong to [N, (N*(N + 1)/2)],
// otherwise we will print -1;
if (Y < N || (2 * Y) > (N * (N + 1))) {
cout << -1 << endl;
return;
}
// Remaining elements to be taken
set s;
for (int i = 1; i <= N; i++) {
s.insert(i);
}
// Generate prefix minimum array
for (int i = 0; i < N; i++) {
// Length remaining
int len = N - i;
int val = findValue(len, Y);
ans[i] = val;
Y -= val;
if (s.find(val) != s.end())
s.erase(val);
}
// Remove duplicates to make array permutation
// So, iterate in reverse order
for (int i = N - 1; i > 0; i--) {
if (ans[i] == ans[i - 1]) {
// Find minimum element not taken
// in the permutation
ans[i] = *s.begin();
s.erase(ans[i]);
}
}
// Print the permutation
for (auto i : ans) {
cout << i << " ";
}
cout << endl;
}
// Driver Code
int main()
{
long long N = 5, Y = 10;
generatePermutation(N, Y);
return 0;
}
Java
// Java program for Generate permutation
// of length N such that sum of all prefix
// minimum of that permutation is Y.
import java.util.*;
class GFG {
// Find the value greedily for the
// current index as discussed in approach
static int findValue(int N, int Y)
{
return Math.min(N, Y + 1 - N);
}
// Function to generate the permutation
static void generatePermutation( int N, int Y)
{
// Store the prefix minimum array first
// then we will convert it to permutation
int[] ans = new int[N];
// If Y should belong to [N, (N*(N + 1)/2)],
// otherwise we will print -1;
if (Y < N || (2 * Y) > (N * (N + 1))) {
System.out.println(-1);
return;
}
// Remaining elements to be taken
Set s = new HashSet();
for (int i = 1; i <= N; i++) {
s.add(i);
}
// Generate prefix minimum array
for (int i = 0; i < N; i++) {
// Length remaining
int len = N - i;
int val = findValue(len, Y);
ans[i] = val;
Y -= val;
if (s.contains(val))
s.remove(val);
}
// Remove duplicates to make array permutation
// So, iterate in reverse order
for (int i = N - 1; i > 0; i--) {
if (ans[i] == ans[i - 1]) {
// Find minimum element not taken
// in the permutation
ans[i] = s.stream().findFirst().get();
s.remove(ans[i]);
}
}
// Print the permutation
for (int i = 0; i < N; i++) {
System.out.print(ans[i] + " ");
}
}
// Driver Code
public static void main (String[] args) {
int N = 5, Y = 10;
generatePermutation(N, Y);
}
}
// This code is contributed by hrithikgarg03188.
Python3
# python3 program for Generate permutation
# of length N such that sum of all prefix
# minimum of that permutation is Y.
# Find the value greedily for the
# current index as discussed in approach
def findValue(N, Y):
return min(N, Y + 1 - N)
# Function to generate the permutation
def generatePermutation(N, Y):
# Store the prefix minimum array first
# then we will convert it to permutation
ans = [0 for _ in range(N)]
# If Y should belong to [N, (N*(N + 1)/2)],
# otherwise we will print -1;
if (Y < N or (2 * Y) > (N * (N + 1))):
print(-1)
return
# Remaining elements to be taken
s = set()
for i in range(1, N+1):
s.add(i)
# Generate prefix minimum array
for i in range(0, N):
# Length remaining
len = N - i
val = findValue(len, Y)
ans[i] = val
Y -= val
if (val in s):
s.remove(val)
# Remove duplicates to make array permutation
# So, iterate in reverse order
for i in range(N-1, -1, -1):
if (ans[i] == ans[i - 1]):
# Find minimum element not taken
# in the permutation
ans[i] = list(s)[0]
s.remove(ans[i])
# Print the permutation
for i in ans:
print(i, end=" ")
print()
# Driver Code
if __name__ == "__main__":
N, Y = 5, 10
generatePermutation(N, Y)
# This code is contributed by rakeshsahni
C#
// C# implementation of above approach
using System;
using System.Collections.Generic;
using System.Linq;
class GFG{
// Find the value greedily for the
// current index as discussed in approach
static int findValue(int N, int Y)
{
return Math.Min(N, Y + 1 - N);
}
// Function to generate the permutation
static void generatePermutation( int N, int Y)
{
// Store the prefix minimum array first
// then we will convert it to permutation
int[] ans = new int[N];
// If Y should belong to [N, (N*(N + 1)/2)],
// otherwise we will print -1;
if (Y < N || (2 * Y) > (N * (N + 1))) {
Console.Write(-1);
return;
}
// Remaining elements to be taken
HashSet s = new HashSet();
for (int i = 1; i <= N; i++) {
s.Add(i);
}
// Generate prefix minimum array
for (int i = 0; i < N; i++) {
// Length remaining
int len = N - i;
int val = findValue(len, Y);
ans[i] = val;
Y -= val;
if (s.Contains(val))
s.Remove(val);
}
// Remove duplicates to make array permutation
// So, iterate in reverse order
for (int i = N - 1; i > 0; i--) {
if (ans[i] == ans[i - 1]) {
// Find minimum element not taken
// in the permutation
ans[i] = s.First();
s.Remove(ans[i]);
}
}
// Print the permutation
for (int i = 0; i < N; i++) {
Console.Write(ans[i] + " ");
}
}
// Driver Code
static public void Main (){
int N = 5, Y = 10;
generatePermutation(N, Y);
}
}
// This code is contributed by code_hunt.
Javascript
5 2 1 4 3
时间复杂度: O(N * log N)。
如果我们使用一个集合,我们可以通过使用两个指针技术使其成为 O(N)。
辅助空间: O(N)