计算总和大于或等于k

时间:2017-07-26 05:07:06

标签: algorithm dynamic-programming

给定一个包含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应该非常小,因为位掩码涉及指数运行时间。

针对上述问题是否有其他有效的算法。

提前致谢。

2 个答案:

答案 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