关键词搜索

源码搜索 ×
×

腾讯面试:你会求二进制中1的个数吗?

发布2022-02-13浏览1447次

详情内容

大家好,我是涛哥。

今天,我们来看一道腾讯面试题:已知n是一个非负整数,求其二进制中1的个数,要求算法效率尽可能高。

这个题目具体什么意思呢?我们假定n = 20,则其二进制为:10100,那么二进制中为1的个数是2个。

这道题看似极其简单,但要找到高效的算法并非易事。接下来,我们循序渐进地看具体解法,并做扩展练习。

                                                         腾讯滨海大厦夜景

常规解法

我们可以直接求出n的二进制值,然后数出值为1的位,这样就能实现题目中的功能,程序如下:

  1. #include<iostream>
  2. using namespace std;
  3. int getNumber1(int n)
  4. {
  5. int r = 2, sum = 0;
  6. while(n)
  7. {
  8. if(1 == n % r)
  9. sum++;
  10. n /= r;
  11. }
  12. return sum;
  13. }
  14. int main()
  15. {
  16. cout << getNumber1(20) << endl; // 结果为2
  17. return 0;
  18. }

 结果为2,答案正确。但是,这是对二进制的每一位进行遍历,效率不高,无法通过腾讯的面试。

移位解法

可把二进制每一位与1进行与运算,也是逐个遍历二进制值,答案正确,但无法通过腾讯面试。

  1. #include<iostream>
  2. using namespace std;
  3. int getNumber2(int n)
  4. {
  5. int sum = 0;
  6. while(n)
  7. {
  8. if(1 == (n & 1))
  9. sum++;
  10. n >>= 1;
  11. }
  12. return sum;
  13. }
  14. int main()
  15. {
  16. cout << getNumber2(20) << endl; // 结果为2
  17. return 0;
  18. }

递归解法

若非必要,请不要在面试中用递归算法,实际工作更是如此。如下答案正确,但无法通过腾讯面试。

  1. #include<iostream>
  2. using namespace std;
  3. int getNumber3(int n)
  4. {
  5. if(0 == n)
  6. {
  7. return 0;
  8. }
  9. return getNumber3(n & (n - 1)) + 1;
  10. }
  11. int main()
  12. {
  13. cout << getNumber3(20) << endl; // 结果为2
  14. return 0;
  15. }

另外,有的朋友可能会疑问,为什么递归关系是这样的呢?先别着急,继续往下看你就会明白了。

最优解法

我们设 n = 20,可以算出 n - 1 的值,请关注n的二进制最后一位1及其后面的0,这一串数字必然是100...的形式,那么 n - 1 的值必然是00...1的形式。

当执行 n & (n - 1) 时,很显然可以看到,其结果就是消掉了n中的最后一位1的值,其余的位保持不变,这是一个很重要的特性。看下面这幅图,你就明白了:

(说明,这个图有点问题,n-1应该是10011,不过不影响结果)

记f(n)为n中二进制为1的个数,则容易得出:f(n) = f(n & (n - 1)) + 1,所以,对应程序如下:

  1. #include<iostream>
  2. using namespace std;
  3. int bestSolution(int n)
  4. {
  5. int sum = 0;
  6. while(n)
  7. {
  8. sum++;
  9. n = n & (n - 1);
  10. }
  11. return sum;
  12. }
  13. int main()
  14. {
  15. cout << bestSolution(20) << endl; // 结果为2
  16. return 0;
  17. }

结果是2,完全正确,而且避免了逐位进行操作,是非常高效的算法,可以通过腾讯的面试。

扩展练习

接下来,我们看看扩展练习,请判断一个正整数是否为2的整数次幂,直接来看如下程序吧:

  1. #include<iostream>
  2. using namespace std;
  3. bool bestSolution(int n)
  4. {
  5. if (n == 0)
  6. {
  7. return false;
  8. }
  9. if ((n & (n - 1)) == 0) // 表明二进制中只有一个1
  10. {
  11. return true;
  12. }
  13. return false;
  14. }
  15. int main()
  16. {
  17. for(int n = 0; n < 100; n++)
  18. {
  19. if (bestSolution(n))
  20. {
  21. cout << n << endl;
  22. }
  23. }
  24. return 0;
  25. }

结果为:

1

2

4

8

16

32

64

好的,bestSolution的解法挺巧妙,必须理解并掌握。有的朋友可能要说:现场谁想得到这种方法啊?

没错,准备充分才能想到,该刷的题,还是要刷,不然面试现场基本懵圈。祝愿大家笔试面试一路顺利。

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载