优化排序列表中的查找

Optimizing find on sorted list

我遇到了一个问题,我们得到了一个排序的数字列表,在某些时候列表中的数字开始重复, 类似于 0,1,2,3,4,5,6,7,8,8,8,我们需要检索重复开始的位置。

以下是我采用的方法...

function find(arr) {  
  let max = arr.length-1
  let min = 0
  do {
    let iter = Math.round((min + max) / 2)
    if (arr[max] == arr[iter])
      max = iter
    else
      min = iter
  } while (min + 1 < max)
  return max
}

arr = [0,1,2,3,4,5,6,7,8,8,8]
console.log(find(arr))

arr = [0,1,2,2,2,2,2,2,2,2,2]
console.log(find(arr))

arr = [0,2,4,6,8,10,10]
console.log(find(arr))

可能有递归的方法,但我想不通
有没有更有效的方法来解决这个问题?

您的解决方案具有 O(log N) 的复杂性。似乎没有比这里的二进制搜索更快的算法。所以你的解决方案没问题

正如 bobra 和 Raymond Chen 所指出的,你不能比 O(log n) 做得更好。但是,您还询问了递归解决方案。给你:

function find(arr, min_idx = 0, max_idx = arr.length - 1) {
  if (min_idx >= max_idx)
    return max_idx 
  let guess = Math.floor((min_idx + max_idx) / 2)
  if (arr[guess] == arr[max_idx])
    return  find(arr, min_idx, guess)  
  return find(arr, guess + 1, max_idx)
}

let arr = [0,1,2,3,4,5,6,7,8,8,8]
console.log(find(arr))

arr = [0,1,2,2,2,2,2,2,2,2,2]
console.log(find(arr))

arr = [2,4,6,8,10,10]
console.log(find(arr))

arr = [10,10,10]
console.log(find(arr))

请注意,这还修复了您的实施中的一个错误。我添加了一个测试用例,当第一个元素等于最大值时,你给出了错误的答案。

我发现所有情况都是:

  • 顺序只重复一次
  • 不重复第一个元素
  • 第一个元素始终为 0

一些具体的例子

[0,1,2,3,4,5,6,7,8,8,8]
[0,1,2,2,2,2,2,2,2,2,2]
[0,2,4,6,8,8,8,8,8,8,8]
[0,3,6,9,9,9,9,9,9,9,9]

最好的解决方案是只有 2 个观测 (last/second) 元素,线性时间