JavaScript循环太慢

时间:2019-10-29 18:04:02

标签: javascript arrays largenumber

我正在处理代码战任务,无法理解如何使此函数在较大的数量== 2000000000000000上更快地工作。该函数的目标非常简单-我只需要计算二进制中所有'1'出现的次数“ left”和“ right”(包括两者)之间的数字表示。

function countOnes(left, right) {
var sum=0;
for (var i=left; i<=right; i++){
    var h=i.toString(2);
    var len=h.length;
    for (var j=0; j<len; j++){
        if (h[j]==1){sum++;}
    }
}
return sum;
}

预先感谢

2 个答案:

答案 0 :(得分:1)

由于按位运算符限制为32位(请参见备注),此解决方案将此限制推至2**53 -1,即JS Number.MAX_SAFE_INTEGER
的值 参见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

const p32 = 2**32

function countOnes_John_MJojo(left, right )
  {
  let sum = 0
  for (let V=left; V<=right; V++)
    {
    for (let N=V;N; N&=N-1) sum++
    for (let N=Math.trunc(V/p32);N; N&=N-1) sum++
    } 
  return sum
  }

/-历史记录:-\
\ -------------- /

使用按位运算符会更快一点:
 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

->逻辑AND
->逻辑右移

function countOnesBin( left, right )
  {
  let sum = 0
  for (let N=left; N<=right; N++)
    {
    let Bin = N
    for(let x = N.toString(2).length;x--;)
      {
      if ( Bin & 1 ) sum++ 
      Bin = Bin >>1
      } 
    } 
  return sum
  }

如@ CodeBling 所示,这可能会更好!

function countOnes_CodeBling  (left, right)
  {
  let sum = 0
  for (let N=left; N<=right; N++)
    {
    for(let Bin = N; Bin > 0; Bin = Bin >> 1)
      { if ( Bin & 1 ) sum++  } 
    } 
  return sum
  }

这是最好的!我不知道这种可能性:感谢@ John

function countOnes_John (left, right)
  {
  let sum = 0
  for (let V=left; V<=right; V++)
    {
    for (let N=V;N; N&=N-1) sum++
    } 
  return sum
  }

答案 1 :(得分:0)

您可以使用split函数避免将块的数量加一减去第二次迭代:

function countOnes(left, right) {
  var sum=0;
  for (var i=left; i<=right; i++){
    var h=i.toString(2);
    sum += h.split('1').length -1;
  }
  return sum;
}

它仍然会很慢,但是比原始代码要快得多。