我有一个号码6
,现在我需要搜索整数数组,如果可以将任何数字加在一起以获得6
。
示例:
1,2,3,5,4
在上面的数组中,我可以使用1+2+3
6
。
我也可以4+2
6
。
问题是如何找到可以总计数字6的个别数字。
答案 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,5
和2,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,5
,2,4
和1,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
中的结果:
答案 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/