[英]Count number of subsets with sum equal to k
給定一個數組,我們需要找出總和正好等於給定 integer k 的子集的數量。 請為這個問題提出一個最佳算法。 這里不需要實際的子集,只需要計數就可以了。
該數組由整數組成,可以是負數也可以是非負數。
示例:Array -> {1,4,-1,10,5} abs sum->9 對於 {4,5} 和 {-1,10},答案應該是 2
這是子集求和問題的變體,它是NP-Hard問題,因此沒有已知的多項式解。 (實際上,子集求和問題說很難找到是否有一個子集求和到給定的總和)。
解決它的可能方法是蠻力(檢查所有可能的子集),或者如果集合包含相對較小的整數,則可以使用偽多項式動態規划技術:
f(i,0) = 1 (i >= 0) //succesful base clause
f(0,j) = 0 (j != 0) //non succesful base clause
f(i,j) = f(i-1,j) + f(i-1,j-arr[i]) //step
將動態規划應用於上述遞歸公式可為您提供O(k*n)
時間和空間解決方案。
使用f(n,k)
調用 [假設數組的索引為 1]。
以下是記憶化的動態編程代碼,用於打印具有給定總和的子集數量。 DP 的重復值存儲在“tmp”數組中。 要獲得 DP 解決方案,首先總是從問題的遞歸解決方案開始,然后將重復值存儲在 tmp 數組中以得出記憶化的解決方案。
#include <bits/stdc++.h>
using namespace std;
int tmp[1001][1001];
int subset_count(int* arr, int sum, int n)
{ ` if(sum==0)
return 1;
if(n==0)
return 0;
if(tmp[n][sum]!=-1)
return tmp[n][sum];
else{
if(arr[n-1]>sum)
return tmp[n][sum]=subset_count(arr,sum, n-1);
else{
return tmp[n][required_sum]=subset_count(arr,sum, n- 1)+subset_count(arr,sum-arr[n-1], n-1);`
}
}
}
// Driver code
int main()
{ ` memset(tmp,-1,sizeof(tmp));
int arr[] = { 2, 3, 5, 6, 8, 10 };
int n = sizeof(arr) / sizeof(int);
int sum = 10; `
cout << subset_count(arr,sum, n);
return 0;
}
這是遞歸解決方案。 它的時間復雜度為 O(2^n) 使用動態規划將時間復雜度提高為二次 O(n^2)
def count_of_subset(arr,sum,n,count):
if sum==0:
count+=1
return count
if n==0 and sum!=0:
count+=0
return count
if arr[n-1]<=sum:
count=count_of_subset(arr,sum-arr[n-1],n-1,count)
count=count_of_subset(arr,sum,n-1,count)
return count
else:
count=count_of_subset(arr,sum,n-1,count)
return count
int numSubseq(vector<int>& nums, int target) {
int size = nums.size();
int T[size+1][target+1];
for(int i=0;i<=size;i++){
for(int j=0;j<=target;j++){
if(i==0 && j!=0)
T[i][j]=0;
else if(j==0)
T[i][j] = 1;
}
}
for(int i=1;i<=size;i++){
for(int j=1;j<=target;j++){
if(nums[i-1] <= j)
T[i][j] = T[i-1][j] + T[i-1][j-nums[i-1]];
else
T[i][j] = T[i-1][j];
}
}
return T[size][target];
}
盡管如果約束條件為:1<=v[i]<=1000,上述基本情況將正常工作
但請考慮:約束條件:0<=v[i]<=1000
上面的基本情況會給出錯誤的答案,考慮一個測試用例:v = [0,0,1] 和 k = 1,根據基本情況,output 將為“1”。
但正確答案是 3:{0,1}{0,0,1}{1}
為了避免這種情況,我們可以 go deep 而不是返回 0,並通過以下方式修復它
C++:
if(ind==0)
{
if(v[0]==target and target==0)return 2;
if(v[0]==target || target==0)return 1;
return 0 ;
}
該解決方案的答案之一是生成 N 的冪集,其中 N 是數組的大小,將等於 2^n。 對於 0 到 2^N-1 之間的每個數字,檢查其二進制表示,並包括該位位於設置位置的數組中的所有值,即 1。 檢查您包含的所有值的總和是否等於所需值。 這可能不是最有效的解決方案,但由於這是一個 NP 難題,因此該問題不存在多項式時間解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.