📜  K 次反转的排列数 | 2套

📅  最后修改于: 2021-09-17 16:05:06             🧑  作者: Mango

给定两个整数NK ,任务是计算刚好有K 次反转的前N 个自然数的排列数。由于计数可能非常大,将其打印为模10 9 + 7

例子:

朴素的方法:请参阅上一篇文章,了解解决问题的最简单的方法。
时间复杂度: O(N*N!)
辅助空间: O(1)

Dynamic Programming using Top-Down Approach:有关自顶向下方法,请参阅本文的前一篇文章。
时间复杂度: O(N*K 2 )
辅助空间: O(N*K)

使用自底向上方法进行动态规划

插图:

请按照以下步骤解决问题:

  • 创建一个辅助数组dp[2][K + 1] ,其中dp[N][K]存储(N – 1) 个数字的所有排列,其中K = (max(K – (N – 1), 0) to K)反转,通过将N数字与它们相加一次。
  • 使用dp[i % 2][K]将在两行之间交换迭代并取j = Max(K – (N – 1), 0) 。所以dp[N[K] = dp[N-1][j] + dp[N-1][j+1] + …. + dp[N – 1][K]
  • 为了计算dp[N][K]不需要做这个额外的K迭代,因为它可以在 O(1) 中从dp[N][K – 1] 获得。所以递推关系由下式给出:
    • dp[N][K] = dp[N][K – 1] + dp[N – 1][K] – dp[N – 1][max(K – (N – 1), 0) – 1]
  • 分别使用变量ijNK 上迭代两个嵌套循环,并根据上述递归关系更新每个 dp 状态。
  • 打印上述步骤后dp[N%2][K]的值作为结果。

下面是上述方法的实现:

C++
// C++ program for the above approach
  
#include 
using namespace std;
  
// Function to count permutations with
// K inversions
int numberOfPermWithKInversion(
    int N, int K)
{
    // Store number of permutations
    // with K inversions
    int dp[2][K + 1];
  
    int mod = 1000000007;
  
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j <= K; j++) {
  
            // If N = 1 only 1 permutation
            // with no inversion
            if (i == 1)
                dp[i % 2][j] = (j == 0);
  
            // For K = 0 only 1 permutation
            // with no inversion
            else if (j == 0)
                dp[i % 2][j] = 1;
  
            // Otherwise Update each dp
            // state as per the reccurrance
            // relation formed
            else
                dp[i % 2][j]
                    = (dp[i % 2][j - 1] % mod
                       + (dp[1 - i % 2][j]
                          - ((max(j - (i - 1), 0) == 0)
                                 ? 0
                                 : dp[1 - i % 2]
                                     [max(j - (i - 1), 0)
                                      - 1])
                          + mod)
                             % mod)
                      % mod;
            ;
        }
    }
  
    // Print final count
    cout << dp[N % 2][K];
}
  
// Driver Code
int main()
{
    // Given N and K
    int N = 3, K = 2;
  
    // Function Call
    numberOfPermWithKInversion(N, K);
  
    return 0;
}


Java
// Java program for the above approach
import java.io.*;
  
class GFG{
  
// Function to count permutations with
// K inversions
static void numberOfPermWithKInversion(int N, int K)
{
      
    // Store number of permutations
    // with K inversions
    int[][] dp = new int[2][K + 1];
  
    int mod = 1000000007;
  
    for(int i = 1; i <= N; i++) 
    {
        for(int j = 0; j <= K; j++) 
        {
              
            // If N = 1 only 1 permutation
            // with no inversion
            if (i == 1)
            {
                dp[i % 2][j] = (j == 0) ? 1 : 0;
            }
  
            // For K = 0 only 1 permutation
            // with no inversion
            else if (j == 0)
                dp[i % 2][j] = 1;
  
            // Otherwise Update each dp
            // state as per the reccurrance
            // relation formed
            else
                {
                 int maxm = Math.max(j - (i - 1));
             dp[i % 2][j] = (dp[i % 2][j - 1] % mod +
                               (dp[1 - i % 2][j] - 
                               ((Math.max(j - (i - 1), 0) == 0) ?
                                   0 : dp[1 - i % 2][maxm, 0) - 1]) +
                                         mod) % mod) % mod;
}
        }
    }
      
    // Print final count
    System.out.println (dp[N % 2][K]);
}
  
// Driver Code
public static void main(String[] args)
{
      
    // Given N and K
    int N = 3, K = 2;
  
    // Function Call
    numberOfPermWithKInversion(N, K);
}
}
  
// This code is contributed by akhilsaini


Python3
# Python3 program for the above approach
  
# Function to count permutations with
# K inversions
def numberOfPermWithKInversion(N, K):
      
    # Store number of permutations
    # with K inversions
    dp = [[0] * (K + 1)] * 2
  
    mod = 1000000007
  
    for i in range(1, N + 1):
        for j in range(0, K + 1):
              
            # If N = 1 only 1 permutation
            # with no inversion
            if (i == 1):
                dp[i % 2][j] = 1 if (j == 0) else 0
  
            # For K = 0 only 1 permutation
            # with no inversion
            elif (j == 0):
                dp[i % 2][j] = 1
  
            # Otherwise Update each dp
            # state as per the reccurrance
            # relation formed
            else:
                var = (0 if (max(j - (i - 1), 0) == 0)
                         else dp[1 - i % 2][max(j - (i - 1), 0) - 1])
                dp[i % 2][j] = ((dp[i % 2][j - 1] % mod +
                                (dp[1 - i % 2][j] -
                                (var) + mod) % mod) % mod)
  
    # Print final count
    print(dp[N % 2][K])
  
# Driver Code
if __name__ == '__main__':
      
    # Given N and K
    N = 3
    K = 2
  
    # Function Call
    numberOfPermWithKInversion(N, K)
  
# This code is contributed by akhilsaini


C#
// C# program for the above approach
using System;
  
class GFG{
  
// Function to count permutations with
// K inversions
static void numberOfPermWithKInversion(int N, int K)
{
      
    // Store number of permutations
    // with K inversions
    int[,] dp = new int[2, K + 1];
  
    int mod = 1000000007;
  
    for(int i = 1; i <= N; i++)
    {
        for(int j = 0; j <= K; j++) 
        {
              
            // If N = 1 only 1 permutation
            // with no inversion
            if (i == 1)
            {
                dp[i % 2, j] = (j == 0) ? 1 : 0;
            }
  
            // For K = 0 only 1 permutation
            // with no inversion
            else if (j == 0)
                dp[i % 2, j] = 1;
  
            // Otherwise Update each dp
            // state as per the reccurrance
            // relation formed
            else
                dp[i % 2, j] = (dp[i % 2, j - 1] % mod + 
                               (dp[1 - i % 2, j] - 
                               ((Math.Max(j - (i - 1), 0) == 0) ?
                                   0 : dp[1 - i % 2, Math.Max(
                                          j - (i - 1), 0) - 1]) +
                                              mod) % mod) % mod;
        }
    }
  
    // Print final count
    Console.WriteLine(dp[N % 2, K]);
}
  
// Driver Code
public static void Main()
{
  
    // Given N and K
    int N = 3, K = 2;
  
    // Function Call
    numberOfPermWithKInversion(N, K);
}
}
  
// This code is contributed by akhilsaini


Javascript


输出:
2

时间复杂度: O(N * K)
辅助空间: O(K)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程