查找总和最接近给定值的元素

时间:2015-05-15 22:38:32

标签: c# algorithm

我已经搜索并阅读了有关此问题的算法,但它们在这种情况下似乎不适用,或者说不够清楚。

我有{{1>} 无符号值,我试图找到 sum最接近指定值N的元素

List的大小可变,平均为500个元素。 此解决方案的性能不是优先级

如果找不到解决方案,已实施的方法应返回单一解决方案或空列表。

现有多个,选择一个元素较少的人。

List<decimal>

3 个答案:

答案 0 :(得分:2)

首先,添加这个方便的组合扩展名:(credits to this answer

public static class EnumerableExtensions
{
    public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
    {
        return k == 0 ? new[] { new T[0] } :
          elements.SelectMany((e, i) =>
            elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
    }
}

然后:

private IEnumerable<decimal> ClosestSum(decimal[] elements, decimal n)
{
    var target = Enumerable.Range(1, elements.Length)
        .SelectMany(p => elements.Combinations(p))
        .OrderBy(p => Math.Abs((decimal)p.Sum() - n))
        .ThenBy(p => p.Count())
        .FirstOrDefault();
    return target ?? new decimal[] { };
}

答案 1 :(得分:1)

这可以通过dynamic programming方法相对于输入按时间线性求解。

    private class Solution
    {
        public int StartIndex;
        public int EndIndex;
        public decimal Sum;
        public int Length
        {
            get { return EndIndex - StartIndex + 1; }
        }

    }

    static List<decimal> Solve(List<decimal> elements, decimal target)
    {
        Solution bestSolution = new Solution { StartIndex = 0, EndIndex = -1, Sum = 0 };
        decimal bestError = Math.Abs(target);
        Solution currentSolution = new Solution { StartIndex = 0, Sum = 0 };

        for (int i = 0; i < elements.Count; i++)
        {
            currentSolution.EndIndex = i;
            currentSolution.Sum += elements[i];
            while (elements[currentSolution.StartIndex] <= currentSolution.Sum - target)
            {
                currentSolution.Sum -= elements[currentSolution.StartIndex];
                ++currentSolution.StartIndex;
            }
            decimal currentError = Math.Abs(currentSolution.Sum - target);
            if (currentError < bestError || currentError == bestError && currentSolution.Length < bestSolution.Length )
            {
                bestError = currentError;
                bestSolution.Sum = currentSolution.Sum;
                bestSolution.StartIndex = currentSolution.StartIndex;
                bestSolution.EndIndex = currentSolution.EndIndex;
            }
        }

        return elements.GetRange(bestSolution.StartIndex, bestSolution.Length);
    }

答案 2 :(得分:1)

我用一种老式的方式输入,但效果很好!

for i in range(len(longlist)):
    longlist.replace(longlist[i],shortlist[i])