这个逻辑是找到数组中的数字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;
答案 0 :(得分:5)
暂停值,然后遍历值v
并对满足w
的所有值v <= w <= v + 5
的相关计数求和,然后找出最大计数:
var buckets = myArray.GroupBy(n => n)
.ToDictionary(g => g.Key, g => g.Count());
var rangeCounts =
buckets.Keys
.Select(v =>
new {
Value = v,
Count = Enumerable.Range(0, 6)
.Sum(i => buckets.ContainsKey(v + i) ?
buckets[v + i] :
0
)
}
);
var bestRange = rangeCounts.MaxBy(x => x.Count);
现在,bestRange.Value
是最佳范围的起点,bestRange.Count
是属于[bestRange.Value, bestRange.Value + 5]
范围内的元素数量。在这里,我使用了MaxBy
。
认为这会让你获得线性表现。构建字典是线性的,构建范围是线性的,MaxBy
是线性的。甚至适用于非分类。
答案 1 :(得分:4)
这里你去:这在O(N)时间和O(1)内存中运行。这形成了其他解决方案中描述的存储桶,然后在您通过阵列时丢弃它们。队列用于跟踪哪些存储桶在可以添加的情况下处于“活动状态”。字典中永远不会有超过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);
答案 2 :(得分:3)
这是一个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;
这里的想法是,如果特定数字a[x]
落在a[i]
的范围内,那么假设a[i+1]
,它将落在x > i
的范围内。 (因此,在原始数组中,a[3]
的值落在a[0]
的范围内,因此它也将落在a[1]
和a[2]
的范围内。
因此索引i
会递增,直到它引用的值超出a[start]
的范围。然后,start
会递增,直到a[i]
再次进入范围。这两个索引以交替的方式向前移动数组。
答案 3 :(得分:0)
这是一个单行LINQ选项。在性能方面不是最好的(它迭代多次)。还是值得注意的。
var result = myArray
.OrderByDescending(i => myArray.Count(i2 => i2 >= i && i2 <= i + 5))
.First();