Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 查找二进制搜索结果的最左重复项_Javascript_Arrays_Algorithm_Binary Search - Fatal编程技术网

Javascript 查找二进制搜索结果的最左重复项

Javascript 查找二进制搜索结果的最左重复项,javascript,arrays,algorithm,binary-search,Javascript,Arrays,Algorithm,Binary Search,假设我有一个有序数组,其中包含大量重复项: var array = [ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, ]; 我还有代码可以在排序数组中对最近值的索引执行二进制搜索: function binaryClosestIndexOf(array, value) { va

假设我有一个有序数组,其中包含大量重复项:

var array = [ 1, 1, 1, 1, 1,
              2, 2, 2, 2, 2,
              3, 3, 3, 3, 3,
              4, 4, 4, 4, 4,
              5, 5, 5, 5, 5, ];
我还有代码可以在排序数组中对最近值的索引执行二进制搜索:

function binaryClosestIndexOf(array, value) {
  var mid,
    lo = 0,
    hi = array.length - 1;

  while (hi - lo > 1) {
    mid = (lo + hi) >>> 1;

    if (array[mid] > value)
      hi = mid;
    else
      lo = mid;
  }

  if (value - array[lo] <= array[hi] - value)
    return lo;
  else 
    return hi;
}
正如我们所看到的,该算法没有问题,它确实返回了最接近的值。但是它返回了一个有趣的混合指数,从最左边到最右边

我想得到最左边的重复索引。我可以在二进制搜索之后引入一个O(n)搜索,然后遍历数组中的每个值,直到找到一个小于当前值的值。我不想这样做


有没有一种方法可以优雅地执行二进制搜索,最终得到最左边的重复值?对于最右边的值的算法也有额外的积分

您可以使用
Array.prototype.indexOf()


<代码>返回数组。索引数组(值数组[Lo] 是二进制搜索,如果你搜索一个精确的值,你不能保证任何位置(右或左测试),它可能在中间。

由于二进制搜索的工作原理是有一个排序的列表,并减少两个因子,因此查找边索引可能很困难

我可以想出两种方法

  • 然后使用一个循环,我认为你可以使用随机性使其成为预期的O(log(n)),正如你可以说最终的循环是预期的恒定时间O(1)
  • 对最接近该数字减去0.000001的索引进行第二次二进制搜索(一旦您知道该值)(在您的列表中为4种情况下,这将始终导致第二次运行搜索3.99999,这将产生15。注意:您应该检查数字(3.999999)的大小写在列表中,并向右移动一个位置以获取值,除非您可以确保列表中存在一定程度的舍入。这将是2*log(n)或O(log(n))

  • 如果列表很长,我认为选项2的预期运行时间实际上会比选项1长,因为2*log(n)将是>log(n)+一个常量,除非您知道会有很多重复项。

    重新排列数据结构以保留值、最左边的位置和计数,即保留数组

    var array = [ 1, 1, 1, 1, 1,
              2, 2, 2, 2, 2,
              3, 3, 3, 3, 3,
              4, 4, 4, 4, 4,
              5, 5, 5, 5, 5, ];
    
    差不多

    var array=[{"v": 1, "l": 0, "c": 5},
               {"v": 2, "l": 5, "c": 5},
               {"v": 3, "l": 10, "c": 5},
               {"v": 4, "l": 15, "c": 5},
               {"v": 5, "l": 20, "c": 5}];
    
    其中“v”表示“值”,“l”表示“最左边的索引”,“c”表示“计数”。对值执行二进制搜索,然后“l”表示最左边的索引,“l”+“c”-1表示最右边的索引

    如果你建立一个约定,你可以将替代结构缩短一点,而不是{“v”:1,“l”:0,“c”:5},使用[1,0,5],其中对应的项分别是value,最左边的索引和count

    vararray=[[1, 0, 5],
              [2, 5, 5],
              [3, 10, 5],
              [4, 15, 5],
              [5, 20, 5]];
    

    arr
    在哪里定义?您唯一能做的就是按原样执行二进制搜索,然后检查目标是否小于结果。(目标为3.9,得到4)如果是这样的话,您已经有了最左边的4个。但是如果不是这样的话,这意味着您已经有了最右边的4个,因此您必须向上迭代,直到遇到最后一个重复项。@guest271314 Typo!”我可以引入一个O(n)在二进制搜索之后进行搜索,遍历数组中的每个值,直到找到一个小于当前值的值。”,我能问一下为什么
    O(n)
    而它肯定是
    O(lg(n))
    ?@user3707125我想进行增量迭代抱歉,我没有想到要进行第二次二进制搜索-这不是很好的编写,也就是说,如果我找到
    array[I]=target
    ,然后测试
    array[--I]
    ,直到找到为止,这是
    O(n)
    (请注意,这是最糟糕的情况!)。你能说明应该如何使用它吗?
    var array=[{"v": 1, "l": 0, "c": 5},
               {"v": 2, "l": 5, "c": 5},
               {"v": 3, "l": 10, "c": 5},
               {"v": 4, "l": 15, "c": 5},
               {"v": 5, "l": 20, "c": 5}];
    
    vararray=[[1, 0, 5],
              [2, 5, 5],
              [3, 10, 5],
              [4, 15, 5],
              [5, 20, 5]];