如何在列表中查找其总和小于或等于数字

时间:2015-08-12 14:19:13

标签: c# performance linq

我有一个数字列表,我想知道列表中哪个数字组合与特定数字(目标)的最接近的总和。(如果有很多组合,找到一个就足够了)

我搜索了很多,并且知道这里有很多解决方案可以找到它们的总和等于特定数字的组合,但没有找到最接近该数字的解决方案。

我还写了一段代码,从零循环到“目标”找到最大的总和,但由于这个过程非常耗时,因为它必须计算100,000个列表,我想知道是否有更有效的方法使用最好是linq。

var List1 = new int[] { 5, 10, 15, 20, 25, 30, 35, 40, 45 };
var target = 40;

int MaxViewers = Convert.ToInt32(txtNoRecordsToAdd.Text);

for (int UserNo = 1; UserNo <= MaxViewers; UserNo++)
{
    for (int No = 1; No <= target; No++)
    {
        var matches = from subset in MyExtensions.SubSetsOf(List1)
                        where subset.Sum() == target
                        select subset;
    }
}

public static class MyExtensions
{
    public static IEnumerable<IEnumerable<T>> SubSetsOf<T>(this IEnumerable<T> source)
    {
        if (!source.Any())
            return Enumerable.Repeat(Enumerable.Empty<T>(), 1);

        // Grab the first element off of the list
        var element = source.Take(1);

        // Recurse, to get all subsets of the source, ignoring the first item
        var haveNots = SubSetsOf(source.Skip(1));

        // Get all those subsets and add the element we removed to them
        var haves = haveNots.Select(set => element.Concat(set));

        // Finally combine the subsets that didn't include the first item, with those that did.
        return haves.Concat(haveNots);
    }

}

1 个答案:

答案 0 :(得分:1)

你好,让我们检查一下实现这个目标的一个棘手的方法,

var List1 = new int[] { 5, 10, 15, 20, 25, 30, 35, 40, 45 };
var target = 40;

int MaxViewers = Convert.ToInt32(txtNoRecordsToAdd.Text);

var closestSubSet = MyExtensions.SubSetsOf(List1)
.Select(o=> new{ SubSet = o, Sum = o.Sum(x=> x)})
.Select(o=> new{ SubSet = o.SubSet, Sum = o.Sum, FromTarget = (target - o.Sum >= 0 ? target - o.Sum : (target - o.Sum) * -1  ) })
.OrderBy(o=> o.FromTarget).FirstOrDefault();

我知道这很棘手我出于某些性能原因进行了第二次选择(没有多次调用和使用它)。这应该找到与您指定的目标最接近的总和^^玩得开心

<强>优化

var List1 = new int [] {5,10,15,20,25,30,35,40,45};     var target = 40;

int MaxViewers = Convert.ToInt32(txtNoRecordsToAdd.Text);
int minClosestTargetRequired = 0;
int closestSum = int.maxValue;
int closestSetIndex = -1;
var subsets = MyExtensions.SubSetsOf(List1);
for(var c = 0 ; c < subsets.Count() ; c++)
{
  int currentSum = subsets[c].Sum(o=> o);
  if(currentSum < closestSum)
  {
    closestSum = currentSum;
    closestSetIndex = c;
  }
  if(closestSum <= minClosestTargetRequired)
    break;
}
Console.WriteLine("Closest Sum Is {0} In Set Index {1},closestSum,closestSetIndex);