给定一个包含n个元素的数组,需要计算其总和大于或等于k的子集数。
例如arr [] = {1,5,9,2,3},k = 16
1 + 5 + 9 + 2 = 17
1 + 5 + 9 + 3 = 18
1 + 5 + 9 + 2 + 3 = 20
5 + 9 + 2 = 16
5 + 9 + 3 = 17
5 + 9 + 2 + 3 = 19
答案是6。
我所知道的一种方法是使用位掩码进行动态编程,并检查sum> = k并增加计数。 这种方法的问题是N应该非常小,因为位掩码涉及指数运行时间。
针对上述问题是否有其他有效的算法。
提前致谢。
答案 0 :(得分:1)
使数组Counts[Sum+1]
,其中Sum是所有元素之和的总和
设置Counts[0] = 1
,其他元素 - 零
永远x=arr[i]
扫描从末尾开始计算数组并递增这些条目,这些条目可以从现有的总和和x
if Counts[j - arr[i]] > 0 then //this check might be omitted
Counts[j] = Counts[j - arr[i]] + Counts[j]
然后对j>=k
复杂性为O(Sum * N)
如果可能总和的范围很大但可能总和的数量不是很高(如arr=[1, 2, 3, 100000000, 100000001]
数组),则可以利用记忆方法并仅在地图中存储真正存在的变体
示例:
arr=[1,2,3,5]
Counts = [1,0,0,0,0,0,0,0,0,0,0,0]
after arr[0]=1
Counts = [1,1,0,0,0,0,0,0,0,0,0,0]
after arr[1]=2
Counts = [1,1,1,1,0,0,0,0,0,0,0,0]
after arr[2]=3
Counts = [1,1,1,2,1,1,1,0,0,0,0,0]
after arr[3]=5
Counts = [1,1,1,2,1,2,2,1,2,1,1,1]
Counts[8] could be composed from 5 and existing Counts[3] with two variants
1+2+5; 3+5
答案 1 :(得分:0)
一种方法是使用递归来创建子集,并在原始集合中省略的元素总和大于total-k时停止递归,其中total是数组所有元素的总和。
这里有一些Java代码说明了这种方法:
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
public class SubSet
{
public static void main(String[] args)
{
Integer[] set = { 1, 5, 9, 2, 3 };
List<List<Integer>> subsets = subsetsK(set, 16);
for (List<Integer> subset : subsets)
{
System.out.println(subset);
}
}
static List<List<Integer>> subsetsK(Integer[] arr, int k)
{
int t = 0;
for (int n : arr) t += n;
List<List<Integer>> subsets = new ArrayList<>();
allSubsets(subsets, arr, new BitSet(arr.length), 0, 0, t - k);
return subsets;
}
public static void allSubsets(List<List<Integer>> subsets, Integer[] arr, BitSet off, int pos, int sum, int lim)
{
if(sum > lim) return;
if(pos == arr.length)
{
subsets.add(toSubset(arr, off));
return;
}
off.set(pos);
allSubsets(subsets, arr, off, pos + 1, sum + arr[pos], lim);
off.clear(pos);
allSubsets(subsets, arr, off, pos + 1, sum, lim);
}
static List<Integer> toSubset(Integer[] arr, BitSet off)
{
List<Integer> ss = new ArrayList<>();
for (int i = 0; i < arr.length; i++)
{
if (!off.get(i))
ss.add(arr[i]);
}
return ss;
}
}
输出:
[5, 9, 3]
[5, 9, 2]
[5, 9, 2, 3]
[1, 5, 9, 3]
[1, 5, 9, 2]
[1, 5, 9, 2, 3]
您可以在此处运行/编辑代码:Ideone