如何找出已定义集合中的哪些数字与另一个数字相加?

时间:2014-03-24 23:13:49

标签: c#

我有一个号码6,现在我需要搜索整数数组,如果可以将任何数字加在一起以获得6

示例:

1,2,3,5,4 

在上面的数组中,我可以使用1+2+3 6

我也可以4+2 6

问题是如何找到可以总计数字6的个别数字。

3 个答案:

答案 0 :(得分:1)

一种可能的选择是获取数组中所有项目组合的列表,然后检查其中哪一项具有目标数字的总和。

我找到了获取组合here的扩展方法(在下面复制)。

public static IEnumerable<T[]> Combinations<T>(this IList<T> argList, int argSetSize)
{
    if (argList == null) throw new ArgumentNullException("argList");
    if (argSetSize <= 0) throw new ArgumentException("argSetSize Must be greater than 0", "argSetSize");
        return combinationsImpl(argList, 0, argSetSize - 1);
}

private static IEnumerable<T[]> combinationsImpl<T>(IList<T> argList, int argStart, int argIteration, List<int> argIndicies = null)
{
    argIndicies = argIndicies ?? new List<int>();
    for (int i = argStart; i < argList.Count; i++)
    {
        argIndicies.Add(i);
        if (argIteration > 0)
        {
            foreach (var array in combinationsImpl(argList, i + 1, argIteration - 1, argIndicies))
            {
                yield return array;
            }
        }
        else
        {
            var array = new T[argIndicies.Count];
            for (int j = 0; j < argIndicies.Count; j++)
            {
                array[j] = argList[argIndicies[j]];
            }

            yield return array;
        }
        argIndicies.RemoveAt(argIndicies.Count - 1);
    }
}

现在您只需要在组中使用您想要的组合数量来调用它。例如,如果要查找2的组:

List<int> ints = new List<int>() { 1, 2, 3, 4, 5 };
int target = 6;

var combs2 = ints.Combinations(2)
    .Where(x => x.Sum() == target);

这将返回1,52,4。然后,您可以将其重复到组中所需的最大项目数。


如果您想立即获得所有结果,请创建一个新的扩展方法,为您进行联合:

public static IEnumerable<T[]> AllCombinations<T>(this IList<T> argsList)
{
    for (int i = 1; i <= argsList.Count; i++)
    {
        foreach (var combo in argsList.Combinations(i))
        {
            yield return combo;
        }
    }
}

然后,您可以通过运行

立即获取所有组合
var allCombos = ints.AllCombinations()
    .Where(x => x.Sum() == target);

因此,对于您的示例,它会在一个集合中返回1,52,41,2,3

答案 1 :(得分:0)

您可以使用 Lipski算法找到导致6的所有组合:

static List<List<int>> FindCombinations(int x)
{
    var combinations = new List<List<int>>();
    var P = new int[10];
    var R = new int[10];

    combinations.Add(Enumerable.Repeat(1,x)); // first combination
    P[1] = x;
    R[1] = 1;
    int d = 1, b, sum;

     while (P[1] > 1)
     {
         sum = 0;
         if (P[d] == 1)
         {
            sum = sum + R[d];
            d = d - 1;
         }
         sum = sum + P[d];
         R[d] = R[d] - 1;
         b = P[d] - 1;

         if (R[d] > 0) d++;
         P[d] = b;
         R[d] = sum/b;
         b = sum%b;

         if (b != 0)
         {
            d++;
            P[d] = b;
            R[d] = 1;
         }
         List<int> temp = new List<int>();
         for (int i = 1; i <= d; i++)
            temp = temp.Concat(Enumerable.Repeat(P[i], R[i])).ToList();

         combinations.Add(temp);
    }

    return combinations;
} 

然后您需要将每个序列与您的数字进行比较:

 var combinations = FindCombinations(6);
 var numbers = new List<int> {1, 2, 3, 5, 4,6};

 var result =
            combinations.Where(x => x.Intersect(numbers).Count() == x.Count)
                .Select(x => x.Intersect(numbers))
                .ToList();

以下是LINQPad中的结果:

enter image description here

答案 2 :(得分:0)

如果你想知道(并发现这些数字)两个数字总和为X,这是一项简单的任务,你可以平均做到O(n)。

HashSet<int> numbers = new HashSet<int>(yourNumberArray);
foreach(int number in numbers)
  if(numbers.Contains(x-number)) 
     Console.WriteLine(number + " " + "numbers[x-number]");

但是当你想知道x1,x2,...,xk数是否为X时,它的NP完全问题并且没有多项式有界解是已知的(也不知道是否存在这样的解) 。如果集合中的项目数量很少(约为20-30),您可以通过枚举所有子集来强制执行结果。

for (int i=1; i< (1 << setSize); ++i)
{
   check does number in current set sum to X by bitwise operations on i 
(treat number binary representation as information about set

 (binary one means item is in set, zero means item is not in set)
}

你也可以将这个问题减少到背包问题并获得伪多项式时间,但是集合中的最大值不应该很大。有关详细信息,请查看:http://www.geeksforgeeks.org/dynamic-programming-subset-sum-problem/