晚上好,我有一个带有n
整数的java数组。我想检查是否有满足条件的条目 k 的子集:
m 条目的总和是 m 的倍数。
我怎样才能尽可能有效地做到这一点?我需要检查n!/k!(n-k)!
个子集。
答案 0 :(得分:2)
您可以使用动态编程。状态是(前缀长度,总和模m,子集中的元素数)。转换是显而易见的:我们要么添加一个数字(增加子集中的元素数量并计算新的模数m),要么我们只增加前缀长度(不添加当前数字)。如果您只需要一个是/否答案,则只能存储最后一层值并应用位优化来更快地计算转换。时间复杂度是O(n * m * k),或者具有比特优化的大约n * m * k / 64运算。空间复杂度为O(m * k)。对于成千上万的元素来说看起来是可行的。通过位优化,我的意思是使用C ++中的bitset之类的东西,它可以使用按位运算同时对一组位执行操作。
答案 1 :(得分:0)
我不喜欢这个解决方案,但它可能适合您的需求
public boolean containsSubset( int[] a , int currentIndex, int currentSum, int depth, int divsor, int maxDepth){
//you could make a, maxDepth, and divisor static as well
//If maxDepthis equal to depth, then our subset has k elements, in addition the sum of
//elements must be divisible by out divsor, m
//If this condition is satisafied, then there exists a subset of size k whose sum is divisible by m
if(depth==maxDepth&¤tSum%divsor==0)
return true;
//If the depth is greater than or equal maxDepth, our subset has more than k elements, thus
//adding more elements can not satisfy the necessary conditions
//additionally we know that if it contains k elements and is divisible by m, it would've satisafied the above condition.
if(depth>=maxdepth)
return false;
//boolean to be returned, initialized to false because we have not found any sets yet
boolean ret = false;
//iterate through all remaining elements of our array
for (int i = currentIndex+1; i < a.length; i++){
//this may be an optimization or this line
//for (int i = currentIndex+1; i < a.length-maxDepth+depth; i++){
//by recursing, we add a[i] to our set we then use an or operation on all our subsets that could
//be constructed from the numbers we have so far so that if any of them satisfy our condition (return true)
//then the value of the variable ret will be true
ret |= containsSubset(a,i,currentSum+a[i],depth+1,divisor, maxDepth);
} //end for
//return the variable storing whether any sets of numbers that could be constructed from the numbers so far.
return ret;
}
然后调用此方法
//this invokes our method with "no numbers added to our subset so far" so it will try adding
// all combinations of other elements to determine if the condition is satisfied.
boolean answer = containsSubset(myArray,-1,0,0,m,k);
编辑:
你可以通过取所有模数(%)m和删除重复来优化它。对于n和/或k值较大但m值较小的示例,这可能是一个非常大的优化。
编辑2:
我列出的上述优化没有帮助。您可能需要重复才能获得正确的信息。我的坏。
快乐的编码!如果您有任何问题,请告诉我们!
答案 2 :(得分:0)
如果数字有下限和上限,则可能更好:
multiple
n
lower_bound * k < multiple < upper_bound * k
multiple
的子集(请参阅Subset Sum problem)。复杂性为O(k^2 * (lower_bound + upper_bound)^2)
。这种方法可以进一步优化,我相信仔细思考。
否则,您可以找到大小为k
的所有子集。复杂性为O(n!)
。使用回溯(伪代码):
function find_subsets(array, k, index, current_subset):
if current_subset.size = k:
add current_subset to your solutions list
return
if index = array.size:
return
number := array[index]
add number to current_subset
find_subsets(array, k, index + 1, current_subset)
remove number from current_subset
find_subsets(array, k, index + 1, current_subset)