在排序的整数数组中查找范围的最大大小

时间:2017-11-30 08:34:36

标签: javascript arrays algorithm sorting

我正在寻找针对以下问题的JavaScript实现。
考虑一个排序数组:

[1,2,5,9,10,12,20,21,22,23,24,26,27]

我想计算增加1的最大范围的长度,不允许重复。

给定示例具有以下范围:

1,2
9,10
20,21,22,23,24 // the maximum range
26,27

因此给定示例的返回值应为5。

我知道如何用明显的解决方案解决这个问题,但我相信有可能用更有效和更短的算法来解决这个问题。

5 个答案:

答案 0 :(得分:2)

简短解决方案

我认为这不比其他人所建议的更有效,但代码相当短,并且只在数组上循环一次,除了第一个元素。不确定是否有任何帮助:

var arr = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27];
var streak = 0, best = 0, bestStart;
for (var i = 1; i < arr.length; i++) {
  if(arr[i]-arr[i-1] === 1) streak++;
  else streak = 0;
  if (streak > best) [best, bestStart] = [streak, i - streak];
}
var bestArr = arr.slice(bestStart, bestStart + best + 1);
console.log('Best streak: '+bestArr);

加快速度

在查看代码之后,我意识到有一种方法可以根据先前的best值检查数组的最后几个元素来略微加快速度:

var arr = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27];
var streak = 0, best = 0, bestStart;
for (var i = 1; i < arr.length; i++) {
  if(best > arr.length - i + streak) break;
  if(arr[i]-arr[i-1] === 1) streak++;
  else streak = 0;
  if (streak > best) [best, bestStart] = [streak, i - streak];
}
var bestArr = arr.slice(bestStart, bestStart + best + 1);
console.log('Best streak: '+bestArr);

答案 1 :(得分:0)

一种可能的解决方案是迭代数组,保持当前范围,只要数字是后继数。如果下一个数字不是前一个数字的后继数,则关闭当前范围并存储其长度 - 将其与最后一个数字的长度进行比较。

在这种方法中,数组只迭代一次,并且范围的最大找到长度在恒定时间内更新,产生O(n)算法,其中n是输入中元素的数量。

类似C#的伪代码的实现可以如下。

int MaximumLength = minus infinity
int CurrentValue = Input[0];
int CurrentLength = 1;

for(int i = 1; i < Input.Length; i++)
{
    if ( CurrentValue + 1 == Input[i] )
    {
        // same range
        CurrentLength = CurrentLength + 1;
    }
    else
    {
        // new range
        MaximumLength = Math.Max(MaximumLength, CurrentLength);
        CurrentLength = 1;
    }
    CurrentValue = Input[i];
}
// check current length again after loop termination
MaximumLength = Math.Max(MaximumLength, CurrentLength);

不可能获得比O(n)更好的效果,因为输入不能在O(n)时间内读取。如果可能的话,那就意味着有些实例的结果不依赖于输入的每个元素,而对于给定的问题则不然。如果最大范围长度为1,则下面草拟的算法Philipp Maurer也将生成O(n)运行时绑定,即输入中没有相邻数字是后继数。

答案 2 :(得分:0)

这样的事情应该首先找到最大长度而不是最后长度。

Let max = 0
Let n = array length
While n > 2
  Let m = 0
  While m <= (array length - n)
    Let first = m
    Let last = m + n - 1 
    Let diff = (value of element 'last' in array) - (value of element 'first' in array)
    if diff = n - 1 then
      max = n
      stop
    end if
    Increase m
  end while
  Decrease n
end while

修改(javascript实施)

var a = [1,2,5,9,10,12,20,21,22,23,24,26,27];
var max = 1;
var n = a.length;
while(n > 2) {
  var m = 0;
  while(m <= a.length - n)
  {
    var first = m;
    var last = m + n - 1;
    var diff = a[last] - a[first];
    if (diff == n - 1 && diff > max) {
      max = n;
      break;
    }
    m++;
    }
  n--;
}

console.log(max);

JSFiddle

答案 3 :(得分:0)

我认为循环并与存储的先前最大长度进行比较是最佳解决方案。也许是这样的:

function findLongestRange(input) {
  let maxLength = 0
  let currentLength = 0

  for (let i = 0; i < input.length; i++) {
    if (i !== input.length) {
      if (input[i] === input[i + 1] - 1) {
        currentLength++
      } else {
        if (maxLength <= currentLength && currentLength !== 0) {
          maxLength = currentLength + 1
        }
        currentLength = 0
      }
    }
  }

  return maxLength
}

const data = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27]
console.log(findLongestRange(data))

这是带有测试的版本,用于检查它与不同输入的工作方式。

const data = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27]

function findLongestRange(input) {
  let maxLength = 0
  let currentLength = 0

  for (let i = 0; i < input.length; i++) {
    if (i !== input.length) {
      if (input[i] === input[i + 1] - 1) {
        currentLength++
      } else {
        if (maxLength <= currentLength && currentLength !== 0) {
          maxLength = currentLength + 1
        }
        currentLength = 0
      }
    }
  }

  return maxLength
}

console.clear()
;[
  [[1,2,5,6,7,1,2], 3],
  [[], 0],
  [data, 5],
  [[1,2,3], 3],
  [[1,3,4,6,8,1], 2],
  [[1,3,5], 0],
].forEach((test, index) => {
  const result = findLongestRange(test[0])
  console.assert(result === test[1], `Fail #${index}: Exp: ${test[1]}, got ${result}`)
})

答案 4 :(得分:-1)

Python回答:

l = [1,2,5,9,10,12,20,21,22,23,24,26,27]
current_range = None
current_range_val = 0
max_range = 0
max_range_val = 0
for i, j in zip(l, l[1:]):
    if j - i == 1:
        current_range_val += 1
        if current_range is None:
            current_range = (i, j)
        current_range = (current_range[0], j)
    else:
        if current_range_val > max_range_val:
            max_range = current_range
            max_range_val = current_range_val
        current_range_val = 0
        current_range = (j, None)

print(max_range)

给出

(20, 24)