找到给定集合中给定数量(允许重复)的所有方法

时间:2011-09-07 18:45:31

标签: algorithm

给定n个元素的数组(例如[1,2])和数字'k'(例如6),找到所有可能的方法来产生sum = k

对于给定的示例,答案是4,因为

1 1 1 1 1 1
1 1 1 1 2
1 1 2 2
2 2 2

我能想到的算法是蛮力,我们模拟所有可能的场景,并在从给定状态停止时我们无法达到结果。

 arr[] = [1,2]
    k = 6
   globalCount =0;
   function findSum(arr,k)
   {
      if(k ==0)
         globalCount++
         return
      else if(k<0)
         return

      for each i in arr{
       arr.erase(i)
       tmp = k
       findSum(arr,tmp)
       while(k>=0){
          findSum(arr,tmp -= i)
      } 
   }

我不确定我的解决方案是否最有效。请评论/更正或显示更好解决方案的指示。

编辑:如果有人能给我代码的运行时复杂性和他们的soln代码,真的很感激。 :) 我认为我的代码复杂度是Big-O(n ^ w)w = k / avg(arr [0] .. arr [n-1])

3 个答案:

答案 0 :(得分:5)

如果你愿意原谅那些花哨的linq技巧,你会发现这个C#解决方案很有用。幸运的是,linq读起来有点像英语。我们的想法是建立解决方案,因为k从0开始并递增,直到达到正确的值。 k的每个值都基于先前的解决方案。但是你需要注意的一件事是确保你找到的新“方式”不是其他人的重新排序。我解决了这个问题,只计算它们是有效的,如果它们被排序的话。 (这只是一个比较)

void Main() {
    foreach (int[] way in GetSumWays(new[] {1, 2}, 6)) {
        Console.WriteLine (string.Join(" ", way));
    }
}

int[][] GetSumWays(int[] array, int k) {
    int[][][] ways = new int[k + 1][][];
    ways[0] = new[] { new int[0] };

    for (int i = 1; i <= k; i++) {
        ways[i] = (
            from val in array
            where i - val >= 0
            from subway in ways[i - val]
            where subway.Length == 0 || subway[0] >= val
            select Enumerable.Repeat(val, 1)
                .Concat(subway)
                .ToArray()
        ).ToArray();
    }

    return ways[k];
}

输出:

1 1 1 1 1 1
1 1 1 1 2
1 1 2 2
2 2 2

它使用动态编程方法,应该比天真的递归方法更快。我认为。我知道它足够快,可以计算在几毫秒内打破一美元的方法。 (242)

答案 1 :(得分:2)

这是分区问题的一个有趣子集。如果允许所有整数,实际上有一个封闭形式的解决方案(参见herehere)。

对“限制分区功能”进行一些谷歌搜索给了我一些线索。 This paper对此问题的几个解决方案进行了非常严格的数学讨论,this one也是如此。

不幸的是,我太懒了,不能编码。他们是非常强烈的解决方案。

答案 2 :(得分:0)

 static void populateSubsetSum(int[]a,int K,int runSum,int idx,ArrayList<ArrayList<Integer>> ans,ArrayList<Integer> al){
    if(idx>=a.length || runSum>K)
        return;
    if(runSum==K){
        ans.add(new ArrayList<>(al));
        return;
    }
    ArrayList<Integer> temp=new ArrayList<>(al);
    temp.add(a[idx]);
    populateSubsetSum(a,K,runSum+a[idx],idx,ans,temp);//when repitions of elements are allowed
    populateSubsetSum(a,K,runSum,idx+1,ans,al);
}

将此函数称为:

populateSubsetSum(a,K,0,0,ans,new ArrayList<>());//array,sum,initial_sum,global 2d list,temp list