嗨!~ 大家好,我是YK菌 🐷 ,一个微系前端 ✨,爱思考,爱总结,爱记录,爱分享 🏹,欢迎关注我呀 😘 ~ [微信公众号:
YK菌]
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
从今天继续来刷《剑指offer(专项突破版)》,原书是Java版本的,这里就是以JavaScript角度来看这些算法题。
剑指 Offer II 003. 前 n 个数字二进制中 1 的个数
给定一个非负整数
n,请计算0到n之间的每个数字的二进制表示中 1 的个数,并输出一个数组。
分析
题目要求:给一个n,然后计算出从0到n的每个数字的二进制形式的1的个数。
最朴素的解法就是使用双重循环首先将十进制数字转换为二进制,然后看每个数字中有多少1即可。
题解
/**
* @param {number} n
* @return {number[]}
*/
var countBits = function(n) {
let result = []
for(let i = 0; i < n + 1; i++){
let binary = i.toString(2)
let item = 0
for(let j = 0; j < binary.length; j++){
if(binary[j]==='1'){
item++
}
}
result.push(item)
}
return result
};
这里使用了双重for循环,外层是;接下来分析内层:如果一个整数共有位,那么它的二进制形式中可能有个。在上述代码中,内部for循环中的代码对每个整数将执行次,因此,上述代码的时间复杂度是。
我们要对解法进行优化,可以仅使用一趟扫描吗?
优化
技巧一:利用 i&(i-1)
之前博文【青训营】月影老师告诉我写好JavaScript的四大技巧——风格优先 - 掘金 (juejin.cn)中我们提到过:通过i &= i - 1 可以去掉二进制中最后面的1
由于i&(i-1)将i的二进制形式中最右边的1变成0,也就是说,整数i的二进制形式中1的个数比i&(i-1)的二进制形式中1的个数多1。所以我们可以优化代码:
/**
* @param {number} n
* @return {number[]}
*/
var countBits = function(n) {
let result = [0]
for(let i = 1; i < n + 1; i++){
result[i] = result[i &(i-1)] + 1
}
return result
};
该解法时间复杂度为
技巧二:利用 i/2
如果正整数i是一个偶数,那么i相当于将i/2左移一位的结果,因此偶数i和i/2的二进制形式中1的个数是相同的。
如果i是奇数,那么i相当于将i/2左移一位之后再将最右边一位设为1的结果,因此奇数i的二进制形式中1的个数比i/2的1的个数多1。
因此可以这样优化代码:
/**
* @param {number} n
* @return {number[]}
*/
var countBits = function(n) {
let result = [0]
for(let i = 1; i < n + 1; i++){
// result[i] = result[~~(i / 2)] + (i%2)
result[i] = result[i >> 1] + (i & 1)
}
return result
};
用i>>1计算i/2,用i&1计算i%2,这是因为位运算比除法运算和求余运算更高效
该解法时间复杂度为
最后,欢迎关注我的专栏,和YK菌做好朋友