我一直在解决日常编码问题并且来到了这个问题.
给定一个整数数组,返回一个新数组,使得新数组的索引i处的每个元素都是原始数组中除i处的数字之外的所有数字的乘积.
例如,如果我们的输入是[1,2,3,4,5],则预期输出将是[120,60,40,30,24].如果我们的输入为[3,2,1],则预期输出为[2,3,6].后续行动:如果你不能使用师?
因此,简单的方法是将数组中的所有元素相乘,然后除以[i],但这会产生问题,即如果I = 0要获得异常错误.
我知道对数组的所有成员执行操作的聚合函数,但是有没有办法修改聚合,以便它对所有成员进行操作,但是有一个,或者是否有其他函数/方法提供此功能?
如果source很小,你可以借助Where例如跳过索引
int[] source = new int[] { 1, 2, 3, 4, 5 };
int[] result = Enumerable
.Range(0, source.Length)
.Select(i => source
.Where((value, index) => index != i) // all items except i-th
.Aggregate((s, a) => s * a)) // should be multiplied
.ToArray();
Console.Write(string.Join(", ", result));
Run Code Online (Sandbox Code Playgroud)
结果:
120, 60, 40, 30, 24
Run Code Online (Sandbox Code Playgroud)
编辑:但是,解决方案有O(N**2)时间复杂性; 如果初始source数组很大,我们可以实现更高效的O(N)代码(是的,我们应该介意零):
int[] source = ...
int[] result;
int zeroCount = source.Count(item => item == 0);
if (zeroCount >= 2) // All zeroes case
result = new int[source.Length];
else if (zeroCount == 1) // All zeroes save one value case
result = source
.Select(v => v == 0
? source.Where(item => item != 0).Aggregate((s, a) => s * a)
: 0)
.ToArray();
else { // No zeroes case
// long, 1L: to prevent integer overflow, e.g. for {1000000, 1000000} input
long total = source.Aggregate(1L, (s, a) => s * a);
result = source
.Select(v => (int)(total / v)) // yes, it's a division...
.ToArray();
}
Run Code Online (Sandbox Code Playgroud)