我正在处理代码战任务,无法理解如何使此函数在较大的数量== 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;
}
预先感谢
答案 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;
}
它仍然会很慢,但是比原始代码要快得多。