arrayMaxConsecutiveSum c#

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++)

作为学习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++)
    {
        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个元素的和,并将其设置为最大值

  • 循环,但每次都从现有的总和中减去i-1处的元素,然后在i+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;
    }