分區問題  


難度級別 中烘焙
經常問 ol石 土磚 亞馬遜 蘋果 彭博社 ByteDance 易趣 Facebook 高盛 谷歌 Microsoft微軟 VMware的 雅虎
排列 動態編程

問題陳述  

在分區問題中,我們給出了一個包含n個元素的集合。 查找給定的集合是否可以分為兩個集合,這些集合的子集中的元素之和相等。

例  

輸入

arr [] = {4,5,11,9,8,3}

產量

解釋

數組可分為2個子集,每個子集的總和分別為{4,5,11}和{9,8,3}

輸入

arr [] = {2,4,11,9,8,3}

產量

沒有

解釋

排列 不能分為相等總和的2個子集。

方法1  

算法

1. 創建ispartition函數以檢查其是否包含2個相等的子集。

2. 在這 功能,

  • 計算數組中元素的總和。
  • 如果總和是奇數,則返回false。
  • 否則在sum = sum / 2的數組上調用SubsetSum。

3. SubsetSum用於查找數組中是否存在一個子集,其總和等於給定的Sum。

4. 在此函數中,SubsetSum使用遞歸方法,

  • 如果最後一個元素大於總和,則忽略它,並通過將大小減小到-1繼續前進。
  •  否則,檢查包括最後一個元素或不包括最後一個元素在內的總和值。
  • 如果sum = 0,則返回true。
  • 如果size = 0但總和不等於零,則返回false。
也可以看看
使用逐字匹配的最長公共前綴

履行

分區問題的C ++程序

#include <bits/stdc++.h>
using namespace std;
 
 
//recursive method
bool SubsetSum(int array[], int n, int sum)
{
   if(sum==0)
   {
     return true;
   }
   if(n==0&&sum!=0)
   {
     return false;
   }
   //last element greater than the sum remove it and continue
   if (array[n-1]>sum)
   {
     return SubsetSum(array, n-1, sum);
   }
   //include last or exclude last
   return SubsetSum(array, n-1, sum) || SubsetSum (array, n-1, sum-array[n-1]);
}
//if sum of elements is odd return false
//else find if there is a subset with sum = sum/2
bool isPartiion(int array[], int n)
{
    int sum = 0;
    for(int i = 0; i < n; i++)
    {
       sum += array[i];
    }
    if(sum%2 != 0)
    {
       return false;
    }
    return SubsetSum(array, n, sum/2);
}
 
//Main function
int main()
{
  int n;
  cin>>n;
  int a[n];
  for(int i=0;i<n;i++)
  {
     cin>>a[i];
  }
  bool x = isPartiion(a,n);
  if(x)
  {
    cout<<"given input array can be divided into two subsets with equal sum";
  }    
  else
  {
    cout<<"given input array cannot be divided into two subsets with equal sum";
  }
  return 0;
}

Java分區問題程序

import java.util.Scanner;
class sum
{
    //recursive method
    public static int SubsetSum(int array[], int n, int sum)
    {
       if(sum==0)
       {
         return 1;
       }
       if(n==0&&sum!=0)
       {
         return 0;
       }
       //last element greater than the sum remove it and continue
       if (array[n-1]>sum)
       {
         return SubsetSum(array, n-1, sum);
       }
       //include last or exclude last
       int x1 = SubsetSum(array, n-1, sum);
       int x2 = SubsetSum (array, n-1, sum-array[n-1]);
       if(x1==1 || x2==1)
           return 1;
       else
           return 0;
    }
    //if sum of elements is odd return false
    //else find if there is a subset with sum = sum/2
    public static int isPartiion(int array[], int n)
    {
        int sum = 0;
        for(int i = 0; i < n; i++)
        {
           sum += array[i];
        }
        if(sum%2 != 0)
        {
           return 0;
        }
        return SubsetSum(array, n, sum/2);
    }
    public static void main(String[] args)  
    { 
        Scanner sr = new Scanner(System.in);
        int n = sr.nextInt();
        int arr[] = new int[n];
        for(int i=0;i<n;i++)
        {
            arr[i] = sr.nextInt();
        }
        int ans = isPartiion(arr,n);
        if(ans==1)
        {
            System.out.println("given input array can be divided into two subsets with equal sum");
        }
        else
        {
            System.out.println("given input array cannot be divided into two subsets with equal sum");
        }
    } 
}
6
1 3 2 1 1 4
given input array can be divided into two subsets with equal sum

分區問題的複雜度分析

時間複雜度

O(2 ^ n) 其中n是給定集中存在的數字。

也可以看看
計算數組中存在其產品的對

空間複雜度

O(N)  因為這裡可能的最大堆棧大小為n。

方法2  

算法

在這裡我們用 動態編程,

1. 創建一個2D數組partition_array大小sum / 2 + 1和n + 1。

2. 在這個數組中

  •  如果元素的一個子集直到array [j-1]的總和等於i,則進行真實存儲。
  • 否則,存儲為假。

3. 返回partition_array [sum / 2] [n]。

履行

分區問題的C ++程序

#include <bits/stdc++.h>
using namespace std;
bool isPartiion(int array[], int n)
{
    int sum = 0,i, j;
    //sum = sum of elements in the array
    for (i = 0; i < n; i++)
    {
      sum += array[i];
    }
    //if sum is odd return false
    if (sum%2 != 0)
    {
       return false;
    }
     //partition table 2d array
    bool partition_array[sum/2+1][n+1];
    for (i = 0; i <= n; i++)
    {
      partition_array[0][i] = true;
    }
    for (i = 1; i <= sum/2; i++)
    {
      partition_array[i][0] = false;     
    }  
     for (i = 1; i <= sum/2; i++)  
     {
       for (j = 1; j <= n; j++)  
       {
         partition_array[i][j] = partition_array[i][j-1];
         if(i >= array[j-1])
         {
           partition_array[i][j] = partition_array[i][j] || partition_array[i - array[j-1]][j-1];
         }
       }        
     }   
     // uncomment this part to print table 
     for (i = 0; i <= sum/2; i++)  
     {
       for (j = 0; j <= n; j++)  
          printf ("%d ",partition_array[i][j]);
       printf("\n");
     }   
     return partition_array[sum/2][n];
}     
 
//Main
int main()
{
  int input_array[] = {1, 2, 3, 6};
  int size = sizeof(input_array)/sizeof(input_array[0]);
  bool x = isPartiion(input_array,size);
  if(x)
  {
    cout<<"given input array can be divided into two subsets with equal sum";
  }    
  else
  {
    cout<<"given input array cannot be divided into two subsets with equal sum";
  }
}

Java分區問題程序

import java.util.Scanner;
class sum
{
    public static int isPartiion(int array[], int n)
    {
        int sum = 0,i, j;
        //sum = sum of elements in the array
        for (i = 0; i < n; i++)
        {
          sum += array[i];
        }
        //if sum is odd return false
        if (sum%2 != 0)
        {
           return 0;
        }
         //partition table 2d array
        int partition_array[][] = new int [sum/2+1][n+1];
        for (i = 0; i <= n; i++)
        {
          partition_array[0][i] = 1;
        }
        for (i = 1; i <= sum/2; i++)
        {
          partition_array[i][0] = 0;     
        }  
         for (i = 1; i <= sum/2; i++)  
         {
           for (j = 1; j <= n; j++)  
           {
             partition_array[i][j] = partition_array[i][j-1];
             if(i >= array[j-1])
             {
               if(partition_array[i][j]==1 || partition_array[i - array[j-1]][j-1]==1)
               {
                   partition_array[i][j]=1;
               }
               else
               {
                   partition_array[i][j]=0;
               }
             }
           }        
         }  
         return partition_array[sum/2][n];
    }     
    public static void main(String[] args)  
    { 
        Scanner sr = new Scanner(System.in);
        int n = sr.nextInt();
        int arr[] = new int[n];
        for(int i=0;i<n;i++)
        {
            arr[i] = sr.nextInt();
        }
        int ans = isPartiion(arr,n);
        if(ans==1)
        {
            System.out.println("given input array can be divided into two subsets with equal sum");
        }
        else
        {
            System.out.println("given input array cannot be divided into two subsets with equal sum");
        }
    } 
}
5
1 2 3 4 5
given input array cannot be divided into two subsets with equal sum

分區問題的複雜度分析

時間複雜度

O(總和* n) 其中sum表示所有元素的加法,n是給定集合的大小。

也可以看看
最小路徑總和

空間複雜度

O(1) 因為我們在這裡不使用任何空間。

參考