📜  序列最小错位

📅  最后修改于: 2021-05-06 22:54:46             🧑  作者: Mango

给定顺序

\ S = {1, 2, 3 \dots N} \

查找在字典上最小的(按字典顺序排列)最小的排列

\ S \

S的排列与S的任何排列一样,使得S中没有两个元素及其排列出现在同一位置。

例子:

Input: 3
Output : 2 3 1
Explanation: The Sequence is 1 2 3.
Possible permutations are (1, 2, 3), (1, 3, 2),
          (2, 1, 3), (2, 3, 1), (3, 1, 2) (3, 2, 1).
Derangements are (2, 3, 1), (3, 1, 2).
Smallest Derangement: (2, 3, 1)

Input : 5
Output : 2 1 4 5 3.
Explanation: Out of all the permutations of 
(1, 2, 3, 4, 5), (2, 1, 4, 5, 3) is the first derangement.

方法1:
我们可以修改本文中显示的方法:最大排列
使用最小堆,我们可以连续获取最少的元素并将其放置在更重要的位置,同时注意保持排列的属性。

复杂度: O(N * log N)

下面是上述方法的实现。

C++
// C++ program to generate smallest derangement
// using priority queue.
#include 
using namespace std;
 
void generate_derangement(int N)
{
    // Generate Sequence and insert into a
    // priority queue.
    int S[N + 1];
    priority_queue, greater > PQ;
    for (int i = 1; i <= N; i++) {
        S[i] = i;
        PQ.push(S[i]);
    }
 
    // Generate Least Derangement
    int D[N + 1];
    for (int i = 1; i <= N; i++) {
        int d = PQ.top();
        PQ.pop();
        if (d != S[i] || i == N) {
            D[i] = d;
        }
        else {
            D[i] = PQ.top();
            PQ.pop();
            PQ.push(d);
        }
    }
 
    if (D[N] == S[N])
       swap(D[N-1], D[N]);
 
    // Print Derangement
    for (int i = 1; i <= N; i++)
        printf("%d ", D[i]);   
    printf("\n");
}
 
// Driver code
int main()
{
    generate_derangement(10);
    return 0;
}


Java
// Java program to generate
// smallest derangement
// using priority queue.
import java.util.*;
class GFG{
 
static void generate_derangement(int N)
{
  // Generate Sequence and insert
  // into a priority queue.
  int []S = new int[N + 1];
   
  PriorityQueue PQ =
                new PriorityQueue <>();
   
  for (int i = 1; i <= N; i++)
  {
    S[i] = i;
    PQ.add(S[i]);
  }
 
  // Generate Least Derangement
  int []D = new int[N + 1];
   
  for (int i = 1; i <= N; i++)
  {
    int d = PQ.peek();
    PQ.remove();
    if (d != S[i] || i == N)
    {
      D[i] = d;
    }
    else
    {
      D[i] = PQ.peek();
      PQ.remove();
      PQ.add(d);
    }
  }
 
  if (D[N] == S[N])
  {
    int t = D[N - 1];
    D[N - 1] = D[N];
    D[N] = t;
  }
 
  // Print Derangement
  for (int i = 1; i <= N; i++)
    System.out.printf("%d ", D[i]);   
  System.out.printf("\n");
}
 
// Driver code
public static void main(String[] args)
{
  generate_derangement(10);
}
}
 
// This code is contributed by Amit Katiyar


Python3
# Python3 program to generate
# smallest derangement
# using priority queue.
def generate_derangement(N) :
     
    # Generate Sequence and insert
    # into a priority queue.
    S = [i for i in range(N + 1)]   
    PQ = []   
    for i in range(1, N + 1) :      
        PQ.append(S[i])
         
    # Generate Least Derangement
    D = [0] * (N + 1)   
    PQ.sort()  
    for i in range(1, N + 1) :     
        PQ.sort()     
        d = PQ[0]
        del PQ[0]    
        if (d != S[i]) or (i == N) :        
            D[i] = d         
        else :        
            PQ.sort()
            D[i] = PQ[0]
            del PQ[0]
            PQ.append(d)           
    if D[N] == S[N] :       
        t = D[N - 1]
        D[N - 1] = D[N]
        D[N] = t
         
    # Print Derangement
    for i in range(1, N + 1) :
        print(D[i], end = " ")       
    print()
     
generate_derangement(10)
 
# This code is contributed by divyeshrabadiya07


C#
// C# program to generate
// smallest derangement
// using priority queue.
using System;
using System.Collections.Generic;
 
class GFG{
 
static void generate_derangement(int N)
{
   
  // Generate Sequence and insert
  // into a priority queue.
  int []S = new int[N + 1];
   
  List PQ = new List ();
   
  for(int i = 1; i <= N; i++)
  {
    S[i] = i;
    PQ.Add(S[i]);
  }
 
  // Generate Least Derangement
  int []D = new int[N + 1];
  PQ.Sort();
  for(int i = 1; i <= N; i++)
  {
    PQ.Sort();
     
    int d = PQ[0];
    PQ.RemoveAt(0);
     
    if (d != S[i] || i == N)
    {
      D[i] = d;
    }
    else
    {
      PQ.Sort();
      D[i] = PQ[0];
      PQ.RemoveAt(0);
      PQ.Add(d);
    }
  }
 
  if (D[N] == S[N])
  {
    int t = D[N - 1];
    D[N - 1] = D[N];
    D[N] = t;
  }
 
  // Print Derangement
  for(int i = 1; i <= N; i++)
    Console.Write(D[i] + " "); 
   
  Console.Write("\n");
}
 
// Driver code
public static void Main(String[] args)
{
  generate_derangement(10);
}
}
 
// This code is contributed by Amit Katiyar


C++
// Efficient C++ program to find smallest
// derangement.
#include 
 
void generate_derangement(int N)
{       
    // Generate Sequence S
    int S[N + 1];
    for (int i = 1; i <= N; i++)
        S[i] = i;
 
    // Generate Derangement
    int D[N + 1];
    for (int i = 1; i <= N; i += 2) {
        if (i == N && i%N!=0) {
 
            // Only if i is odd
            // Swap D[N-1] and D[N]
            int temp=D[N]
            D[N] = D[N - 1];
            D[N - 1] = temp;
        }
        else {
            D[i] = i + 1;
            D[i + 1] = i;
        }
    }
 
    // Print Derangement
    for (int i = 1; i <= N; i++)
        printf("%d ", D[i]);   
    printf("\n");
}
 
// Driver Program
int main()
{
    generate_derangement(10);
    return 0;
}


Java
// Efficient Java program to find
// smallest derangement.
class GFG
{
     
static void generate_derangement(int N)
{
    // Generate Sequence S
    int S[] = new int[N + 1];
    for (int i = 1; i <= N; i++)
        S[i] = i;
 
    // Generate Derangement
    int D[] = new int[N + 1];
    for (int i = 1; i <= N; i += 2)
    {
        if (i == N)
        {
 
            // Only if i is odd
            // Swap S[N-1] and S[N]
            D[N] = S[N - 1];
            D[N - 1] = S[N];
        }
        else
        {
            D[i] = i + 1;
            D[i + 1] = i;
        }
    }
 
    // Print Derangement
    for (int i = 1; i <= N; i++)
        System.out.print(D[i] + " ");
    System.out.println();
}
 
// Driver Program
public static void main(String[] args)
{
    generate_derangement(10);
}
}
 
// This code is contributed by Arnab Kundu


Python3
# Efficient Python3 program to find
# smallest derangement.
 
def generate_derangement(N):
     
    # Generate Sequence S
    S = [0] * (N + 1)
    for i in range(1, N + 1):
        S[i] = i
 
    # Generate Derangement
    D = [0] * (N + 1)
    for i in range(1, N + 1, 2):
        if i == N:
 
            # Only if i is odd
            # Swap S[N-1] and S[N]
            D[N] = S[N - 1]
            D[N - 1] = S[N]
        else:
            D[i] = i + 1
            D[i + 1] = i
 
    # Print Derangement
    for i in range(1, N + 1):
        print(D[i], end = " ")
    print()
 
# Driver Code
if __name__ == '__main__':
    generate_derangement(10)
     
# This code is contributed by PranchalK


C#
// Efficient C# program to find
// smallest derangement.
using System;
 
class GFG
{
     
static void generate_derangement(int N)
{
    // Generate Sequence S
    int[] S = new int[N + 1];
    for (int i = 1; i <= N; i++)
        S[i] = i;
 
    // Generate Derangement
    int[] D = new int[N + 1];
    for (int i = 1; i <= N; i += 2)
    {
        if (i == N)
        {
 
            // Only if i is odd
            // Swap S[N-1] and S[N]
            D[N] = S[N - 1];
            D[N - 1] = S[N];
        }
        else
        {
            D[i] = i + 1;
            D[i + 1] = i;
        }
    }
 
    // Print Derangement
    for (int i = 1; i <= N; i++)
        Console.Write(D[i] + " ");
    Console.WriteLine();
}
 
// Driver Program
public static void Main()
{
    generate_derangement(10);
}
}
 
// This code is contributed
// by Akanksha Rai


PHP


输出:

2 1 4 3 6 5 8 7 10 9 

方法二
由于我们给出了一个非常具体的序列,即

S_i = i \ \ \forall i <= N

我们可以更有效地计算答案。
将原始序列分为两个元素对,然后交换每个对中的元素。
如果N为奇数,则需要再次交换最后一对。

绘画作品

复杂度:我们最多执行N / 2 + 1交换,因此复杂度为O(N)。

为什么这种方法有效
此方法是方法1的非常特定的应用,并且基于观察。给定序列的性质,在位置i处,我们已经知道可以放置的最小元素,即i + 1或i-1。由于已经给定了S的最小排列,因此很明显,排列必须从2开始而不是从1开始,即形式为i + 1(i = 1)。下一个元素的格式为i – 1。之后的元素将是i + 1,然后是下一个i –1。此模式将一直持续到结束。
此操作最容易理解为S元素对中相邻元素的交换。
如果我们可以在恒定时间内确定最少的元素,那么就可以消除堆的复杂性开销。因此,复杂度从O(N * log N)降低为O(N)。

下面是上述方法的实现:

C++

// Efficient C++ program to find smallest
// derangement.
#include 
 
void generate_derangement(int N)
{       
    // Generate Sequence S
    int S[N + 1];
    for (int i = 1; i <= N; i++)
        S[i] = i;
 
    // Generate Derangement
    int D[N + 1];
    for (int i = 1; i <= N; i += 2) {
        if (i == N && i%N!=0) {
 
            // Only if i is odd
            // Swap D[N-1] and D[N]
            int temp=D[N]
            D[N] = D[N - 1];
            D[N - 1] = temp;
        }
        else {
            D[i] = i + 1;
            D[i + 1] = i;
        }
    }
 
    // Print Derangement
    for (int i = 1; i <= N; i++)
        printf("%d ", D[i]);   
    printf("\n");
}
 
// Driver Program
int main()
{
    generate_derangement(10);
    return 0;
}

Java

// Efficient Java program to find
// smallest derangement.
class GFG
{
     
static void generate_derangement(int N)
{
    // Generate Sequence S
    int S[] = new int[N + 1];
    for (int i = 1; i <= N; i++)
        S[i] = i;
 
    // Generate Derangement
    int D[] = new int[N + 1];
    for (int i = 1; i <= N; i += 2)
    {
        if (i == N)
        {
 
            // Only if i is odd
            // Swap S[N-1] and S[N]
            D[N] = S[N - 1];
            D[N - 1] = S[N];
        }
        else
        {
            D[i] = i + 1;
            D[i + 1] = i;
        }
    }
 
    // Print Derangement
    for (int i = 1; i <= N; i++)
        System.out.print(D[i] + " ");
    System.out.println();
}
 
// Driver Program
public static void main(String[] args)
{
    generate_derangement(10);
}
}
 
// This code is contributed by Arnab Kundu

Python3

# Efficient Python3 program to find
# smallest derangement.
 
def generate_derangement(N):
     
    # Generate Sequence S
    S = [0] * (N + 1)
    for i in range(1, N + 1):
        S[i] = i
 
    # Generate Derangement
    D = [0] * (N + 1)
    for i in range(1, N + 1, 2):
        if i == N:
 
            # Only if i is odd
            # Swap S[N-1] and S[N]
            D[N] = S[N - 1]
            D[N - 1] = S[N]
        else:
            D[i] = i + 1
            D[i + 1] = i
 
    # Print Derangement
    for i in range(1, N + 1):
        print(D[i], end = " ")
    print()
 
# Driver Code
if __name__ == '__main__':
    generate_derangement(10)
     
# This code is contributed by PranchalK

C#

// Efficient C# program to find
// smallest derangement.
using System;
 
class GFG
{
     
static void generate_derangement(int N)
{
    // Generate Sequence S
    int[] S = new int[N + 1];
    for (int i = 1; i <= N; i++)
        S[i] = i;
 
    // Generate Derangement
    int[] D = new int[N + 1];
    for (int i = 1; i <= N; i += 2)
    {
        if (i == N)
        {
 
            // Only if i is odd
            // Swap S[N-1] and S[N]
            D[N] = S[N - 1];
            D[N - 1] = S[N];
        }
        else
        {
            D[i] = i + 1;
            D[i + 1] = i;
        }
    }
 
    // Print Derangement
    for (int i = 1; i <= N; i++)
        Console.Write(D[i] + " ");
    Console.WriteLine();
}
 
// Driver Program
public static void Main()
{
    generate_derangement(10);
}
}
 
// This code is contributed
// by Akanksha Rai

的PHP


输出:

2 1 4 3 6 5 8 7 10 9 

注意:如果我们对S本身执行交换操作,则辅助空间可以减小为O(1)。