给定一个数组arr []和多个查询,在每个查询中,我们必须检查数组中是否存在总和等于给定数字的子集。
例子:
Input : arr[] = {1, 2, 3};
query[] = {5, 3, 8}
Output : Yes, Yes, No
There is a subset with sum 5, subset is {2, 3}
There is a subset with sum 3, subset is {1, 2}
There is no subset with sum 8.
Input : arr[] = {4, 1, 5};
query[] = {7, 9}
Output : No, Yes
There is no subset with sum 7.
There is a subset with sum 9, subset is {4, 5}
这个想法是在C++中使用位集容器。使用位集,我们可以预先计算O(n)中数组中所有子集和的存在,并仅在O(1)中回答后续查询。
我们基本上使用位数组bit []表示数组中元素的子集总和。 bit []的大小应至少为所有数组元素的总和加1以回答所有查询。如果x是给定数组的子集和,则将bit [x]保持为1,否则返回false。请注意,假定索引从0开始。
For every element arr[i] of input array,
we do following
// bit[x] will be 1 if x is a subset
// sum of arr[], else 0
bit = bit | (bit << arr[i])
这是如何运作的?
Let us consider arr[] = {3, 1, 5}, we need
to whether a subset sum of x exists or not,
where 0 ≤ x ≤ Σarri.
We create a bitset bit[10] and reset all the
bits to 0, i.e., we make it 0000000000.
Set the 0th bit, because a subset sum of 0
exists in every array.
Now, the bit array is 0000000001
Apply the above technique for all the elements
of the array :
Current bitset = 0000000001
After doing "bit = bit | (bit << 3)",
bitset becomes 0000001001
After doing "bit | (bit << 1)",
bitset becomes 0000011011
After doing "bit | (bit << 5)",
bitset becomes 1101111011
最后,我们将位数组设置为1101111011,因此,如果bit [x]为1,则x的子集和存在,否则不存在。我们可以清楚地观察到,除了2和7之外,数组中还存在着0到9之间所有数字的子集和。
这是一个C++实现:
// C++ program to answer subset sum queries using bitset
#include
using namespace std;
// Maximum allowed query value
# define MAXSUM 10000
// function to check whether a subset sum equal to n
// exists in the array or not.
void processQueries(int query[], int nq, bitset bit)
{
// One by one process subset sum queries
for (int i=0; i= MAXSUM)
{
cout << "NA, ";
continue;
}
// Else if x is a subset sum, then x'th bit
// must be set
bit[x]? cout << "Yes, " : cout << "No, ";
}
}
// function to store all the subset sums in bit vector
void preprocess(bitset &bit, int arr[], int n)
{
// set all the bits to 0
bit.reset();
// set the 0th bit because subset sum of 0 exists
bit[0] = 1;
// Process all array elements one by one
for (int i = 0; i < n; ++i)
// Do OR of following two
// 1) All previous sums. We keep previous value
// of bit.
// 2) arr[i] added to every previous sum. We
// move all previous indexes arr[i] ahead.
bit |= (bit << arr[i]);
}
// Driver program
int main()
{
int arr[] = {3, 1, 5};
int query[] = {8, 7};
int n = sizeof(arr) / sizeof(arr[0]);
int nq = sizeof(query) / sizeof(query[0]);
// a vector of MAXSUM number of bits
bitset bit;
preprocess(bit, arr, n);
processQueries(query, nq, bit);
return 0;
}
输出:
Yes, No,
时间复杂度:O(n)用于预先计算,O(1)用于后续查询,其中n是数组中元素的数量。
有关此方法的空间要求,请参阅http://stackoverflow.com/questions/12459563/what-is-the-size-of-bitset-in-c。