C# 提高嵌套循环的性能

C# 提高嵌套循环的性能,c#,arrays,performance,sorting,loops,C#,Arrays,Performance,Sorting,Loops,此逻辑用于查找数组中的数字n,其中n到n+5之间的范围将包含数组中最多的数字。我提出了一个解决方案,但它需要一个嵌套的循环,因此速度有点慢。有没有办法提高它的性能?提前谢谢 保证数组已排序 int[] myArray = new int[]{1,2,4,5,7,9,15,19}; int bestNumber = 0; int MaxMatchFound = 0; for (int o = 0; o < myArray.Length; o++) { int TempMatchF

此逻辑用于查找数组中的数字n,其中n到n+5之间的范围将包含数组中最多的数字。我提出了一个解决方案,但它需要一个嵌套的循环,因此速度有点慢。有没有办法提高它的性能?提前谢谢

保证数组已排序

int[] myArray = new int[]{1,2,4,5,7,9,15,19};
int bestNumber = 0;
int MaxMatchFound = 0;

for (int o = 0; o < myArray.Length; o++)
{

    int TempMatchFound = 0;

    for (int i = 0; i < myArray.Length; i++)
    {
        if (myArray[i] >= myArray[o] && myArray[i] <= (myArray[o] + 5))
        {
            TempMatchFound++;
        }
    }
    if (TempMatchFound > MaxMatchFound)
    {
        bestNumber = myArray[o];
        MaxMatchFound = TempMatchFound;
    }

}

return bestNumber;
int[]myArray=newint[]{1,2,4,5,7,9,15,19};
int-bestNumber=0;
int MaxMatchFound=0;
for(into=0;o=myArray[o]&&myArray[i]MaxMatchFound)
{
bestNumber=myArray[o];
MaxMatchFound=TempMatchFound;
}
}
返回最佳编号;

这里有一个单行LINQ选项。性能不是最好的(它会重复多次)。仍然值得注意

var result = myArray
             .OrderByDescending(i => myArray.Count(i2 => i2 >= i && i2 <= i + 5))
             .First();
var result=myArray

.OrderByDescending(i=>myArray.Count(i2=>i2>=i&&i2现在开始:这在O(N)时间内运行,而O(1)时间内运行内存。这会形成其他解决方案中描述的存储桶,然后在数组中移动时丢弃它们。队列用于跟踪哪些存储桶处于“活动”状态,即它们可以添加到哪些存储桶中。字典中的条目永远不会超过6个,队列也不会超过6个

int[] myArray = new int[]{1,2,4,5,7,9,15,19};
Dictionary<int, int> counts = new Dictionary<int, int>();
Queue<int> q = new Queue<int>();

int n = 0;
int currentMaxCount = 0;


for(int i = 0; i < myArray.Length; i++)
{
    var currentNum = myArray[i];
    if(counts.ContainsKey(currentNum))
    {
        counts[currentNum]++;
    }
    else
    {
        counts[currentNum] = 1;
        q.Enqueue(currentNum);
    }

    for(int j = 1; j <= 5; j++)
    {
        if(counts.ContainsKey(currentNum - j))
            counts[currentNum - j]++;
    }

    if(q.Peek() + 5 < currentNum)
    {
        if(counts[q.Peek()] > currentMaxCount)
        {
            currentMaxCount = counts[q.Peek()];
            n = q.Peek();
        }
        counts.Remove(q.Dequeue());

    }
}

while(q.Count > 0)
{
    if(counts[q.Peek()] > currentMaxCount)
    {
        currentMaxCount = counts[q.Peek()];
        n = q.Peek();
    }
    counts.Remove(q.Dequeue());
}

Console.WriteLine("There are {0} matches between {1} and {2}", currentMaxCount, n, n + 5);
int[]myArray=newint[]{1,2,4,5,7,9,15,19};
字典计数=新字典();
队列q=新队列();
int n=0;
int currentMaxCount=0;
for(int i=0;i0)
{
如果(计数[q.Peek()]>currentMaxCount)
{
currentMaxCount=计数[q.Peek()];
n=q.Peek();
}
counts.Remove(q.Dequeue());
}
WriteLine(“在{1}和{2}之间有{0}个匹配项”,currentMaxCount,n,n+5);

将值放入桶中,然后在值
v
上循环,并对满足
v的所有值
w
的相关计数求和。这里有一个解决方案,即O(n)并使用O(1)额外空间,而不考虑范围

它只通过一次数组,总是进行2N次比较。我看不出有任何方法可以改进这个算法,尽管肯定有一些微优化可以使实现速度提高一点

private int FindRange(int[] myArray)
{
    const int range = 5;
    int start = 0;
    int maxMatchFound = 0;
    int maxIndex = 0;
    for (int i = 0; i < myArray.Length; ++i)
    {
        if (myArray[i] > myArray[start] + range)
        {
            int matchLength = i - start;
            if (matchLength > maxMatchFound)
            {
                maxMatchFound = matchLength;
                maxIndex = start;
            }
            // move forward until within range
            do
            {
                ++start;
            } while (myArray[i] > myArray[start] + range);
        }
    }
    // Final check, from myArray[start] to end of array
    int len = myArray.Length - start;
    if (len > maxMatchFound)
    {
        maxMatchFound = len;
        maxIndex = start;
    }
    return maxIndex;
private int FindRange(int[]myArray)
{
常数int范围=5;
int start=0;
int maxMatchFound=0;
int maxIndex=0;
对于(int i=0;imyArray[start]+范围)
{
int matchLength=i-开始;
如果(匹配长度>maxMatchFound)
{
maxMatchFound=匹配长度;
maxIndex=开始;
}
//向前移动直到在范围内
做
{
++开始;
}while(myArray[i]>myArray[start]+范围);
}
}
//最终检查,从myArray[开始]到阵列结束
int len=myArray.Length-start;
如果(len>maxMatchFound)
{
maxMatchFound=len;
maxIndex=开始;
}
返回最大索引;
这里的想法是,如果一个特定的数字
a[x]
a[i]
的范围内,那么它将在
a[i+1]
的范围内,假设
x>i
(因此在原始数组中,
a[3]
处的值在
a[0]的范围内)
,因此它也将在
a[1]
a[2]
的范围内


因此,索引
i
递增,直到它引用的值超出
a[start]
的范围。然后,
start
递增,直到
a[i]
再次进入范围。两个索引以交替的方式在数组中向前移动。

它需要执行多快,以及您将使用多大的数据集来执行此操作?您能保证数组最初排序吗?请注意,如果您确保输入数据已排序,则可以在一个值出现时立即跳出内部循环大于上限,您可以在当前项之后的项开始内部循环,而不是在开始处开始。@JoelCoehoorn是的,它已排序。我忘了提到。另外,为了解释@Servy:performance的第一个注释,它是相对的,而且成本很高。相对的,就样本数据集的大小而言,您现在拥有的已经是m了速度不够快。成本很高,因为程序员的时间通常比较昂贵(而且很少)而不是cpu时间。优化此代码所花费的时间是以优化其他代码为代价的。如果您需要优化某些东西,您是在这里还是在其他地方花费这些时间取决于您必须查看的数据量以及cpu可以在其上花费的时间。他特别询问如何提高性能。虽然此方法非常有用,但ess代码,它比OP已经有的速度慢,这是一个非常糟糕的答案。对于嵌套循环,看起来是n^2。在任何情况下,这也需要O(n)额外的空间。这不一定是坏事,但你应该指出。这不是O(n^2)因为该范围内的元素少于5个。该嵌套循环实际上是O(1)。只有在不允许重复的情况下才是如此。更新以保持O(n)时间和重复情况下的正确性。进一步更新以仅使用常量空间。@ghord那是什么?将单个项添加到字典中需要O(1)时间。(当摊销时,它可以在这里。)你这样做N次,那就是O(N)。+1一个有趣的解决方案。我想知道它是否可以在恒定的额外空间中完成。是的,它可以用O(1)在O(N)中完成
private int FindRange(int[] myArray)
{
    const int range = 5;
    int start = 0;
    int maxMatchFound = 0;
    int maxIndex = 0;
    for (int i = 0; i < myArray.Length; ++i)
    {
        if (myArray[i] > myArray[start] + range)
        {
            int matchLength = i - start;
            if (matchLength > maxMatchFound)
            {
                maxMatchFound = matchLength;
                maxIndex = start;
            }
            // move forward until within range
            do
            {
                ++start;
            } while (myArray[i] > myArray[start] + range);
        }
    }
    // Final check, from myArray[start] to end of array
    int len = myArray.Length - start;
    if (len > maxMatchFound)
    {
        maxMatchFound = len;
        maxIndex = start;
    }
    return maxIndex;