arrayMaxConsecutiveSum c#
作为学习c#的一部分,我参与了代码信号挑战。到目前为止,一切都很顺利,除了标题中提到的测试 问题是,当数组长度为10^5且连续元素数(k)为1000时,我的代码的效率不足以在3秒内运行。我的代码运行如下:arrayMaxConsecutiveSum c#,c#,arrays,C#,Arrays,作为学习c#的一部分,我参与了代码信号挑战。到目前为止,一切都很顺利,除了标题中提到的测试 问题是,当数组长度为10^5且连续元素数(k)为1000时,我的代码的效率不足以在3秒内运行。我的代码运行如下: int arrayMaxConsecutiveSum(int[] inputArray, int k) { int sum = 0; int max = 0; for (int i = 0; i <= inputArray.Length-k; i++)
int arrayMaxConsecutiveSum(int[] inputArray, int k) {
int sum = 0;
int max = 0;
for (int i = 0; i <= inputArray.Length-k; i++)
{
sum = inputArray.Skip(i).Take(k).Sum();
if (sum > max)
max = sum;
}
return max;
}
intarraymaxconsecurivesum(int[]输入阵列,intk){
整数和=0;
int max=0;
对于(int i=0;i max)
最大值=总和;
}
返回最大值;
}
网站中所有可见的测试都正常运行,但当涉及到隐藏测试时,在测试20中,出现了一个错误,说明
19/20测试通过。测试20超出执行时间限制:程序超出执行时间限制。对于任何可能的输入,确保它在几秒钟内完成执行
我也尝试过解锁解决方案,但在c#上,代码与此类似,但他没有使用LINQ。我还尝试将它与隐藏测试一起运行,但出现了相同的错误,这与它在未通过所有测试时作为解决方案提交的方式很奇怪
有没有更快的方法来求数组的和
我还想解锁隐藏的测试,但我认为它不会给我任何具体的解决方案,因为问题仍然存在。似乎您正在为每个循环添加k个数字。此伪代码应该更有效:
这里的区别在于每个循环中的加法数。在原始代码中,为每个循环添加k个元素,在该代码中,在每个循环中,减去一个元素,然后将一个元素添加到现有的和中,因此这是2个操作与k个操作的比较。当k对于大型数组变大时,代码开始变慢。对于这种特定情况,我建议您不要使用
Skip
方法,因为它每次都在集合上迭代。您可以在上检查跳过实现。复制代码以供参考
public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, int count) {
if (source == null) throw Error.ArgumentNull("source");
return SkipIterator<TSource>(source, count);
}
static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count) {
using (IEnumerator<TSource> e = source.GetEnumerator()) {
while (count > 0 && e.MoveNext()) count--;
if (count <= 0) {
while (e.MoveNext()) yield return e.Current;
}
}
}
你可以查看这个dotnet提琴,在这里你可以比较时差。通过基准测试,我建议您仔细研究。在使用LINQ和考虑性能时,您需要小心。并不是说它很慢,而是它可以很容易地将一个大的操作隐藏在一个单词后面。在这方面:
sum = inputArray.Skip(i).Take(k).Sum();
Skip(i)
和Take(k)
都将花费大约相当于for
循环的时间,通过数千行,并且该行将针对主循环中的数千项中的每一项运行
没有更快的神奇命令,相反,您必须重新考虑您的方法,在循环中执行最少的步骤。在这种情况下,您可以记住每个步骤的总和,只添加或删除单个值,而不是每次都重新计算整个过程
public static int arrayMaxConsecutiveSum(int[] inputArray, int k)
{
int sum = 0;
int max = 0;
for (int i = 0; i <= inputArray.Length-k; i++)
{
// Add the next item
sum += inputArray[i];
// Limit the sum to k items
if (i > k) sum -= inputArray[i-k];
// Is this the highest sum so far?
if (sum > max)
max = sum;
}
return max;
}
公共静态int-arraymaxonsecurivesum(int[]输入阵列,int k)
{
整数和=0;
int max=0;
对于(inti=0;ik)sum-=inputArray[i-k];
//这是目前为止最高的金额吗?
如果(总和>最大值)
最大值=总和;
}
返回最大值;
}
这是我的解决方案
public int ArrayMaxConsecutiveSum(int[] inputArray, int k)
{
int max = inputArray.Take(k).Sum();
int sum = max;
for (int i = 1; i <= inputArray.Length - k; i++)
{
sum = sum - inputArray[i- 1] + inputArray[i + k - 1];
if (sum > max)
max = sum;
}
return max;
}
public int-arraymaxonsecurivesum(int[]输入阵列,int-k)
{
int max=inputArray.Take(k.Sum();
整数和=最大值;
对于(int i=1;i max)
最大值=总和;
}
返回最大值;
}
是的,您不应该在大型列表上运行take&skip,但这里有一个纯粹基于LINQ的解决方案,它既易于理解,又能在足够的时间内执行任务。是的,迭代代码的性能仍然优于它,因此您必须为您的用例进行权衡。因为尺寸或容易理解的基准
intarraymaxconsecurivesum(int[]输入阵列,intk)
{
var sum=inputArray.Take(k).sum();
返回Math.Max(总和,可枚举范围(k,inputArray.Length-k)
.Max(i=>sum+=inputArray[i]-inputArray[i-k]);
}
两者的时间复杂度都是O(n*k),它只需要是O(n)@TheGeneral-明白了。这可以用O(n)来完成,正如Paddy提出的双指针方法。使用dotnetfiddle,我以前的代码给了我1.67Mb的内存,执行时间为0.328s。我现在看到了新代码的巨大差异,它在最后一次运行时运行:4:46:04 pm Compile:0.156s Execute:0s Memory:813kb CPU:0s立即运行。谢谢仍然困惑于如何分离前3个元素使代码高效运行。我还想提高投票率,不幸的是我还有不到15票reputation@Dorokun192归结到时间复杂度,你的是O(n*k),这个是,O(n)你需要使用O(n)
算法来解决这个问题,例如。
public int ArrayMaxConsecutiveSum(int[] inputArray, int k)
{
int max = inputArray.Take(k).Sum();
int sum = max;
for (int i = 1; i <= inputArray.Length - k; i++)
{
sum = sum - inputArray[i- 1] + inputArray[i + k - 1];
if (sum > max)
max = sum;
}
return max;
}