📌  相关文章
📜  计算将集合划分为k个子集的方式数量

📅  最后修改于: 2021-04-24 15:50:27             🧑  作者: Mango

给定两个数字n和k,其中n表示集合中的多个元素,请找到多种将集合划分为k个子集的方法。
例子:

Input: n = 3, k = 2
Output: 3
Explanation: Let the set be {1, 2, 3}, we can partition
             it into 2 subsets in following ways
             {{1,2}, {3}},  {{1}, {2,3}},  {{1,3}, {2}}  

Input: n = 3, k = 1
Output: 1
Explanation: There is only one way {{1, 2, 3}}

递归解决方案

  • 方法:首先,让我们定义一个递归解决方案以找到第n个元素的解决方案。有两种情况。
    1. 前面的n – 1个元素被划分为k个分区,即S(n-1,k)方式。将第n个元素放入先前的k个分区之一。因此, count = k * S(n-1,k)
    2. 前面的n-1个元素被划分为k-1个分区,即S(n-1,k-1)方式。将第n个元素放入新分区(单元素分区)中,因此count = S(n-1,k-1)
    3. 总计数= k * S(n-1,k)+ S(n-1,k-1)。
  • 算法:
    1. 创建一个接受两个参数n和k的递归函数。该函数将n个元素的分区总数返回k个集合。
    2. 处理基本情况。如果n = 0或k = 0或k> n,则返回0,因为不能有任何子集。如果n等于k或k等于1,则返回1。
    3. 否则,按如下方式计算值: S(n,k)= k * S(n-1,k)+ S(n-1,k-1) ,即使用已恢复的参数调用递归函数并计算S的值(n,k)。
    4. 返回总和。
  • 执行:
C++
// A C++ program to count number of partitions
// of a set with n elements into k subsets
#include
using namespace std;
 
// Returns count of different partitions of n
// elements in k subsets
int countP(int n, int k)
{
  // Base cases
  if (n == 0 || k == 0 || k > n)
     return 0;
  if (k == 1 || k == n)
      return 1;
 
  // S(n+1, k) = k*S(n, k) + S(n, k-1)
  return  k*countP(n-1, k) + countP(n-1, k-1);
}
 
// Driver program
int main()
{
   cout <<  countP(3, 2);
   return 0;
}


Java
// Java  program to count number
// of partitions of a set with
// n elements into k subsets
import java.io.*;
 
class GFG
{
    // Returns count of different
    // partitions of n elements in
    // k subsets
    public static int countP(int n, int k)
    {
       // Base cases
       if (n == 0 || k == 0 || k > n)
          return 0;
       if (k == 1 || k == n)
          return 1;
 
       // S(n+1, k) = k*S(n, k) + S(n, k-1)
       return (k * countP(n - 1, k)
              + countP(n - 1, k - 1));
    }
 
    // Driver program
    public static void main(String args[])
    {
       System.out.println(countP(3, 2));
 
    }
}
 
//This code is contributed by Anshika Goyal.


Python 3
# A Python3 program to count number
# of partitions of a set with n
# elements into k subsets
 
# Returns count of different partitions
# of n elements in k subsets
def countP(n, k):
     
    # Base cases
    if (n == 0 or k == 0 or k > n):
        return 0
    if (k == 1 or k == n):
        return 1
     
    # S(n+1, k) = k*S(n, k) + S(n, k-1)
    return (k * countP(n - 1, k) +
                countP(n - 1, k - 1))
 
# Driver Code
if __name__ == "__main__":
    print(countP(3, 2))
 
# This code is contributed
# by Akanksha Rai(Abby_akku)


C#
// C# program to count number
// of partitions of a set with
// n elements into k subsets
using System;
 
class GFG {
     
    // Returns count of different
    // partitions of n elements in
    // k subsets
    public static int countP(int n, int k)
    {
         
        // Base cases
        if (n == 0 || k == 0 || k > n)
            return 0;
        if (k == 1 || k == n)
            return 1;
     
        // S(n+1, k) = k*S(n, k) + S(n, k-1)
        return (k * countP(n - 1, k)
                + countP(n - 1, k - 1));
    }
 
    // Driver program
    public static void Main()
    {
        Console.WriteLine(countP(3, 2));
    }
}
 
// This code is contributed by anuj_67.


PHP
 $n)
        return 0;
    if ($k == 1 || $k == $n)
        return 1;
     
    // S(n+1, k) = k*S(n, k)
    // + S(n, k-1)
    return $k * countP($n - 1, $k) +
            countP($n - 1, $k - 1);
}
 
    // Driver Code
    echo countP(3, 2);
 
// This code is contributed by aj_36
?>


Javascript


C++
// A Dynamic Programming based C++ program to count
// number of partitions of a set with n elements
// into k subsets
#include
using namespace std;
 
// Returns count of different partitions of n
// elements in k subsets
int countP(int n, int k)
{
  // Table to store results of subproblems
  int dp[n+1][k+1];
 
  // Base cases
  for (int i = 0; i <= n; i++)
     dp[i][0] = 0;
  for (int i = 0; i <= k; i++)
     dp[0][k] = 0;
 
  // Fill rest of the entries in dp[][]
  // in bottom up manner
  for (int i = 1; i <= n; i++)
     for (int j = 1; j <= i; j++)
       if (j == 1 || i == j)
          dp[i][j] = 1;
       else
          dp[i][j] = j * dp[i - 1][j] + dp[i - 1][j - 1];
 
  return dp[n][k];
}
 
// Driver program
int main()
{
   cout <<  countP(5, 2);
   return 0;
}


Java
// A Dynamic Programming based Java program to count
// number of partitions of a set with n elements
// into k subsets
class GFG{
 
// Returns count of different partitions of n
// elements in k subsets
static int countP(int n, int k)
{
    // Table to store results of subproblems
    int[][] dp = new int[n+1][k+1];
     
    // Base cases
    for (int i = 0; i <= n; i++)
    dp[i][0] = 0;
    for (int i = 0; i <= k; i++)
    dp[0][k] = 0;
     
    // Fill rest of the entries in dp[][]
    // in bottom up manner
    for (int i = 1; i <= n; i++)
    for (int j = 1; j <= k; j++)
    if (j == 1 || i == j)
        dp[i][j] = 1;
    else
        dp[i][j] = j * dp[i - 1][j] + dp[i - 1][j - 1];
         
        return dp[n][k];
     
}
 
// Driver program
public static void main(String[] args )
{
    System.out.println(countP(5, 2));
}
}
 
// This code is contributed by Rajput-Ji


Python3
# A Dynamic Programming based Python3 program
# to count number of partitions of a set with
# n elements into k subsets
 
# Returns count of different partitions
# of n elements in k subsets
def countP(n, k):
     
    # Table to store results of subproblems
    dp = [[0 for i in range(k + 1)]
             for j in range(n + 1)]
 
    # Base cases
    for i in range(n + 1):
        dp[i][0] = 0
 
    for i in range(k + 1):
        dp[0][k] = 0
 
    # Fill rest of the entries in
    # dp[][] in bottom up manner
    for i in range(1, n + 1):
        for j in range(1, k + 1):
            if (j == 1 or i == j):
                dp[i][j] = 1
            else:
                dp[i][j] = (j * dp[i - 1][j] +
                                dp[i - 1][j - 1])
                 
    return dp[n][k]
 
# Driver Code
if __name__ == '__main__':
    print(countP(5, 2))
 
# This code is contributed by
# Surendra_Gangwar


C#
// A Dynamic Programming based C# program 
// to count number of partitions of a 
// set with n elements into k subsets
using System;
 
class GFG
{
 
// Returns count of different partitions of n
// elements in k subsets
static int countP(int n, int k)
{
    // Table to store results of subproblems
    int[,] dp = new int[n + 1, k + 1];
     
    // Base cases
    for (int i = 0; i <= n; i++)
        dp[i, 0] = 0;
    for (int i = 0; i <= k; i++)
        dp[0, k] = 0;
     
    // Fill rest of the entries in dp[][]
    // in bottom up manner
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= k; j++)
            if (j == 1 || i == j)
                dp[i, j] = 1;
            else
                dp[i, j] = j * dp[i - 1, j] + dp[i - 1, j - 1];
             
        return dp[n, k];
     
}
 
// Driver code
public static void Main( )
{
    Console.Write(countP(5, 2));
}
}
 
// This code is contributed by Ita_c.


PHP


Javascript


  • 输出:
3
  • 复杂度分析:
    • 时间复杂度: O(2 ^ n)。
      对于每个n值,调用两个递归函数。更具体地说,时间复杂度是指数级的。
    • 空间复杂度: O(n)(由于调用堆栈)。

高效的解决方案

  • 方法:以上递归解的时间复杂度是指数的。可以通过减少重叠的子问题来优化解决方案。以下是countP(10,7)的递归树。子问题countP(8,6)CP(8,6)被多次调用。

  • 因此,此问题具有动态编程问题的两个属性(请参阅类型1和类型2)。像其他典型的动态编程(DP)问题一样,通过使用所示的递归公式以自底向上的方式构造临时数组dp [] [] ,可以避免相同子问题的重新计算。
    接下来是减少子问题以优化问题的复杂性。这可以通过两种方式完成:
    1. 自下而上的方式:保持递归结构完整,并将值存储在哈希图或2D数组中。然后仅计算一次该值,然后在下次调用该函数时返回该值。
    2. 自上而下的方式:保留大小为n * k的2D数组,其中dp [i] [j]表示将i个元素划分为j个集合的总数。填写dp [i] [0]和dp [0] [i]的基本情况。对于值(i,j),需要dp [i-1] [j]和dp [i-1] [j-1]的值。因此,将DP从第0行填充到n,从第0列填充到k。
  • 算法:
    1. 创建大小为(n + 1)*(k + 1)的Dp数组dp [n + 1] [k + 1]。
    2. 填写基本案例的值。对于从0到n的所有i值,填充dp [i] [0] = 0 ,对于从0到k的i的所有值,填充dp [0] [k] = 0
    3. 运行一个嵌套循环,外循环从1到n,内循环从1到k。
    4. 对于索引i和j(分别为外循环和内循环),计算dp [i] [j] = j * dp [i – 1] [j] + dp [i – 1] [j – 1] ,如果j = = 1或i == j,计算dp [i] [j] = 1。
    5. 打印值dp [n] [k]
  • 执行:

C++

// A Dynamic Programming based C++ program to count
// number of partitions of a set with n elements
// into k subsets
#include
using namespace std;
 
// Returns count of different partitions of n
// elements in k subsets
int countP(int n, int k)
{
  // Table to store results of subproblems
  int dp[n+1][k+1];
 
  // Base cases
  for (int i = 0; i <= n; i++)
     dp[i][0] = 0;
  for (int i = 0; i <= k; i++)
     dp[0][k] = 0;
 
  // Fill rest of the entries in dp[][]
  // in bottom up manner
  for (int i = 1; i <= n; i++)
     for (int j = 1; j <= i; j++)
       if (j == 1 || i == j)
          dp[i][j] = 1;
       else
          dp[i][j] = j * dp[i - 1][j] + dp[i - 1][j - 1];
 
  return dp[n][k];
}
 
// Driver program
int main()
{
   cout <<  countP(5, 2);
   return 0;
}

Java

// A Dynamic Programming based Java program to count
// number of partitions of a set with n elements
// into k subsets
class GFG{
 
// Returns count of different partitions of n
// elements in k subsets
static int countP(int n, int k)
{
    // Table to store results of subproblems
    int[][] dp = new int[n+1][k+1];
     
    // Base cases
    for (int i = 0; i <= n; i++)
    dp[i][0] = 0;
    for (int i = 0; i <= k; i++)
    dp[0][k] = 0;
     
    // Fill rest of the entries in dp[][]
    // in bottom up manner
    for (int i = 1; i <= n; i++)
    for (int j = 1; j <= k; j++)
    if (j == 1 || i == j)
        dp[i][j] = 1;
    else
        dp[i][j] = j * dp[i - 1][j] + dp[i - 1][j - 1];
         
        return dp[n][k];
     
}
 
// Driver program
public static void main(String[] args )
{
    System.out.println(countP(5, 2));
}
}
 
// This code is contributed by Rajput-Ji

Python3

# A Dynamic Programming based Python3 program
# to count number of partitions of a set with
# n elements into k subsets
 
# Returns count of different partitions
# of n elements in k subsets
def countP(n, k):
     
    # Table to store results of subproblems
    dp = [[0 for i in range(k + 1)]
             for j in range(n + 1)]
 
    # Base cases
    for i in range(n + 1):
        dp[i][0] = 0
 
    for i in range(k + 1):
        dp[0][k] = 0
 
    # Fill rest of the entries in
    # dp[][] in bottom up manner
    for i in range(1, n + 1):
        for j in range(1, k + 1):
            if (j == 1 or i == j):
                dp[i][j] = 1
            else:
                dp[i][j] = (j * dp[i - 1][j] +
                                dp[i - 1][j - 1])
                 
    return dp[n][k]
 
# Driver Code
if __name__ == '__main__':
    print(countP(5, 2))
 
# This code is contributed by
# Surendra_Gangwar

C#

// A Dynamic Programming based C# program 
// to count number of partitions of a 
// set with n elements into k subsets
using System;
 
class GFG
{
 
// Returns count of different partitions of n
// elements in k subsets
static int countP(int n, int k)
{
    // Table to store results of subproblems
    int[,] dp = new int[n + 1, k + 1];
     
    // Base cases
    for (int i = 0; i <= n; i++)
        dp[i, 0] = 0;
    for (int i = 0; i <= k; i++)
        dp[0, k] = 0;
     
    // Fill rest of the entries in dp[][]
    // in bottom up manner
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= k; j++)
            if (j == 1 || i == j)
                dp[i, j] = 1;
            else
                dp[i, j] = j * dp[i - 1, j] + dp[i - 1, j - 1];
             
        return dp[n, k];
     
}
 
// Driver code
public static void Main( )
{
    Console.Write(countP(5, 2));
}
}
 
// This code is contributed by Ita_c.

的PHP


Java脚本


  • 输出:
15
  • 复杂度分析:
    • 时间复杂度: O(n * k)。
      填充了大小为n * k的2dp数组,因此时间复杂度为O(n * k)。
    • 空间复杂度: O(n * k)。
      需要额外的2D DP阵列。