俄罗斯贵宾会-俄罗斯贵宾会官网
做最好的网站

别人家的面试题:一个整数是否是“4”的N次幂

更快的 countBit

上一个版本的 countBit 的时间复杂度已经是 O(logN) 了,难道还可以更快吗?当然是可以的,我们不需要去判断每一位是不是“1”,也能知道 n 的二进制中有几个“1”。

有一个诀窍,是基于以下一个定律:

  • 对于任意 n, n ≥ 1,有如下等式成立:

countBit(n & (n - 1)) === countBit(n) - 1

1
countBit(n & (n - 1)) === countBit(n) - 1

这个很容易理解,大家只要想一下,对于任意 n,n – 1 的二进制数表示正好是 n 的二进制数的最末一个“1”退位,因此 n & n – 1 正好将 n 的最末一位“1”消去,例如:

  • 6 的二进制数是 110, 5 = 6 – 1 的二进制数是 101,6 & 5 的二进制数是 110 & 101 == 100
  • 88 的二进制数是 1011000,87 = 88 – 1 的二进制数是 1010111,88 & 87 的二进制数是 1011000 & 1010111 == 1010000

于是,我们有了一个更快的算法:

版本3

function countBit(n){ var ret = 0; while(n > 0){ ret++; n &= n - 1; } return ret; } function countBits(nums){ var ret = []; for(var i = 0; i <= nums; i++){ ret.push(countBit(i)); } return ret; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function countBit(n){
    var ret = 0;
    while(n > 0){
        ret++;
        n &= n - 1;
    }
    return ret;
}
 
function countBits(nums){
   var ret = [];
   for(var i = 0; i <= nums; i++){
       ret.push(countBit(i));
   }
   return ret;
}

上面的 countBit(88) 只循环 3 次,而“版本2”的 countBit(88) 却需要循环 7 次。

优化到了这个程度,是不是一切都结束了呢?从算法上来说似乎已经是极致了?真的吗?再给大家 30 秒时间思考一下,然后再往下看。


其他版本

上面的版本已经符合了我们的需求,时间复杂度是 O(1),不用循环和递归。

此外,我们还可以有其他的版本,它们严格来说有的还是“犯规”,但是我们还是可以学习一下这些思路:

版本4:用 Math.sqrt

JavaScript

function isPowerOfFour(num) { num = Math.sqrt(num); return num > 0 && num === (0|num) && (num & (num-1)) === 0; };

1
2
3
4
function isPowerOfFour(num) {
    num = Math.sqrt(num);
    return num > 0 && num === (0|num) && (num & (num-1)) === 0;
};

版本5:用正则表达式

JavaScript

function isPowerOfFour(num) { return /^1(00)*$/g.test(num.toString(2)); };

1
2
3
function isPowerOfFour(num) {
    return /^1(00)*$/g.test(num.toString(2));
};

以上就是所有的内容,这道题有非常多种思路,相当有趣,也比较考验基本功。如果你有自己的思路,可以留言参与讨论。

下一期我们讨论另外一道题,这道题比这两道题要难一些,但也更有趣:给定一个正整数 n,将它拆成至少两个正整数之和,对拆出的正整数求乘积,返回能够得到的乘积最大的结果

想一想你的解法是什么?你能够尽可能减少算法的时间复杂度吗?期待你的答案~~

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

图片 1 图片 2

3 赞 8 收藏 5 评论

不用循环和递归

其实这道题真心有好多种思路,计算指数之类的对数学系学霸们完全不是问题嘛:

版本2

JavaScript

const log4 = Math.log(4); function isPowerOfFour(num){ var n = Math.log(num) / log4; return n === (0|n); }

1
2
3
4
5
const log4 = Math.log(4);
function isPowerOfFour(num){
    var n = Math.log(num) / log4;
    return n === (0|n);
}

嗯,通过对数公式 logm(n) = log(n) / log(m) 求出指数,然后判断指数是不是一个整数,这样就可以不用循环和递归解决问题。而且,还要注意细节,可以将 log4 当做常量抽取出来,这样不用每次都重复计算,果然是学霸范儿。

不过呢,利用 Math.log 方法也算是某种意义上的犯规吧,有没有不用数学函数,用原生方法来解决呢?

当然有了!而且还不止一种,大家可以继续想30秒,要至少想出一种哦 ——


统计“1”的个数

给定一个非负整数 num,对于任意 i,0 ≤ i ≤ num,计算 i 的值对应的二进制数中 “1” 的个数,将这些结果返回为一个数组。

例如:

当 num = 5 时,返回值为 [0,1,1,2,1,2]。

/** * @param {number} num * @return {number[]} */ var countBits = function(num) { //在此处实现代码 };

1
2
3
4
5
6
7
/**
* @param {number} num
* @return {number[]}
*/
var countBits = function(num) {
    //在此处实现代码
};

别人家的面试题:一个整数是否是“4”的N次幂

2016/05/30 · 基础技术 · 2 评论 · 算法

本文作者: 伯乐在线 - 十年踪迹 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者

这是 leetcode.com 的第二篇。与上一篇一样,我们讨论一道相对简单的问题,因为学习总讲究循序渐进。而且,就算是简单的问题,追求算法的极致的话,其中也是有大学问的。

关于作者:十年踪迹

图片 3

月影,奇舞团团长,热爱前端开发,JavaScript 程序猿一枚,能写代码也能打杂卖萌说段子。 个人主页 · 我的文章 · 14 ·     

图片 4

“4”的整数次幂

给定一个32位有符号整数(32 bit signed integer),写一个函数,检查这个整数是否是“4”的N次幂,这里的N是非负整数。

例如:

  • 给定 num = 16,返回 true,因为 16 = 42
  • 给定 num = 5,返回 flase

附加条件: 你能够不用循环和递归吗?

本文由俄罗斯贵宾会发布于Web前端,转载请注明出处:别人家的面试题:一个整数是否是“4”的N次幂

您可能还会对下面的文章感兴趣: