Algorithms_入门基础_如何使用最高效的方式来判断一个数是否是2的N次方

2021-08-17 10:56:31 浏览数 (1)


Question

引入… 先看个阿里巴巴的面试题吧

如何使用最高效的方式来判断一个数是否是2的N次方? 先思考下哈

… … … … … … … … … … … … … …

Answer 1.0

分析下:

2的N次方嘛 ,举个例子 2 4 8 16是 2的N次方, 6 , 10 不是2的N次方。

2的N次方 ====> 就可以看成 这个数是不是可以拆成 N个2相乘嘛

那根据这个思路的话 ,写个伪代码

代码语言:javascript复制
while(n>1){
  n % 2 == 0  ---> 如果除以2不为0 ,肯定不是2的N次方 
  n = n / 2 ;	---> 继续除以2 (即我们上面说的拆成N个2),循环判断 
}

分析好了,我们来用Java语言实现下

代码语言:javascript复制
/**
 * @author 小工匠
 * @version v1.0
 * @create 2019-11-19 21:22
 * @motto show me the code ,change the word
 * @blog https://artisan.blog.csdn.net/
 * @description
 **/

public class Test {

    /**
     * 思路:
     * 如果某个数除以2 不等于0 ,最起码已经不是2的倍数了,更不要是2的N次方了 ,
     * 比如  3 ,5 ,7这种数字
     * 利用该特性循环判断
     *
     * @param args
     */
    public static void main(String[] args) {

        int n = 6;// 原始数值
        int temp = n; // 临时变量

        while (temp > 1) {// while循环
            if (temp % 2 == 0) { // 判断是否是2的倍数
                temp = temp / 2; // 除以2 继续下一次的循环判断
                System.out.println(temp == 1 ? ("原始数值【"   n   "】是2的N次方") : ("分析中...."   temp));
            } else {// 不是2的倍数,肯定不是2的N次方了,直接break跳出循环
                System.out.println(n   "不是2的N次方");
                break;// 终止循环
            }
        }
    }
}

好了,算是实现了, 其实看看这个代码是比较挫的,有没有更好的思路呢 ?

提示一下: 按位与运算


Answer 2.0 按位与运算 &

为啥能想到这种思路,其实也是要靠积累的,对数字要有足够的敏感,看到某个十进制的数,可以马上想到对应的二进制数。

八位二进制嘛 ,为啥是8位,请移步下方的须知 我们来看下几个数字

2 ,4 ,8 ,16

我们来看下 2 ,4 ,8 ,16 这几个十进制的是 对应的 二进制 ,咋算的 请移步下方的须知

代码语言:javascript复制
2 = 10        ---->补位凑成8位  -----> 00000010
4 = 100       ---->补位凑成8位  -----> 00000100
8= 1000       ---->补位凑成8位  -----> 00001000
16=10000      ---->补位凑成8位  -----> 00010000

接下来我们看下 比2 4 8 16 小1的十进制整数,对应的二进制

代码语言:javascript复制
2 = 10            ---->补位凑成8位  -----> 00000010
1 = 01            ---->补位凑成8位  -----> 00000001

4 = 100           ---->补位凑成8位  -----> 00000100
3 = 011           ---->补位凑成8位  -----> 00000011


8 = 1000          ---->补位凑成8位  -----> 00001000
7 = 0111          ---->补位凑成8位  -----> 00000111 


16 = 10000        ---->补位凑成8位  -----> 00010000
15 = 01111        ---->补位凑成8位  -----> 00001111    

按二进制位进行“与”运算 ,只有两个数的二进制同时为1,结果才为1,否则为0。

我们看下上面的规律哈 n 和 n-1 这两个十进制的整数 ,按照二进制进行 按位与运算后,为0,那么这个n就是2的N次方。

伪代码如下

代码语言:javascript复制
if((n & (n-1)) == 0)) -----> n 就是 2的次方

接下来我们用java实现以下

代码语言:javascript复制
/**
 * @author 小工匠
 * @version v1.0
 * @create 2019-11-19 21:27
 * @motto show me the code ,change the word
 * @blog https://artisan.blog.csdn.net/
 * @description
 **/
public class TestA {

    /**
     * 思路:
     *      按位与运算 &  , 两个数字按照二进制的形式进行"与"运算 ,如果结果为0 ,则是2的N次方
     * @param args
     */
    public static void main(String[] args) {

        int  n = 128 ;
        System.out.println((n&(n-1)) == 0 ? n   "是2的N次方"  : n   "不是2的N次方");

    }
}

须知

十进制转二进制

十进制整数转换为二进制整数采用"除2取余,逆序排列"法。

具体做法:

用2整除十进制整数,可以得到一个商和余数;

再用2去除商,又会得到一个商和余数,如此进行,直到商为小于1时为止,

然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。

一图胜千言 ,来吧


八位二进制

我们常说 “八位二进制” ,到底是啥意思嘞 ?

说起二进制 ,其实就要从计算机的的组成-电子元件说起, 这些元件一般都是只有两种稳定的工作状态,用高、低两个电位表示“0”和“1”在物理上是最容易实现的。

那八位二进制又是什么妖魔鬼怪呢? 我们知道 电脑的最小存储单位是字节Byte ,即我们常说的大B, 一个字节, 是由八位二进制位组成的,就是这八位数字只是由“0”和“1”两个数字组成 ,比如 11111000,00000001,00000101等等。

八位二进制 就是一个字节(Byte)的大小。

1个英文字母、英文标点、半角数字 在计算机是以八位二进制数保存 就是一个字节大小,

1个汉字(包括中文标点 全角数字)就是2个字节 (十六位二进制)

1位二进制大小就是1bit ,就是我们说的 小b。


在计算机科学中,bit通常用于表示信息的最小单位,也可以被称作是二进制位。在计算机学科中,bit一般用0和1表示。Byte也就是人们常说的字节,通常由8个位(8bit)组成一个字节(1Byte)

比如我们常见的基本类型的取值范围

bit与Byte之间可以进行换算,具体的换算关系为:1Byte=8bit

在计算机网络或者是网络运营商中,一般而言,宽带速率的单位用bps(或b/s)表示;bps表示比特每秒即表示每秒钟传输多少位信息,是bit per second的缩写 小b 。 在实际所说的1M带宽的意思是1Mbps(是兆比特每秒Mbps不是兆字节每秒MBps)。

代码语言:javascript复制
1B=8b 1B/s=8b/s(或1Bps=8bps)

1KB=1024B 1KB/s=1024B/s

1MB=1024KB 1MB/s=1024KB/s

规范提示:实际书写规范中B应表示Byte(字节),b应表示bit(比特),但在平时的实际书写中有的把bit和Byte都混写为b ,如把Mb/s和MB/s都混写为Mb/s,导致人们在实际计算中因单位的混淆而出错。切记注意!!!


按位与运算 &

定义: 参加运算的两个数,按二进制位进行“与”运算

运算规则:只有两个数的二进制同时为1,结果才为1,否则为0。

比如 0 & 0= 0 ,0 & 1= 0,1 & 0= 0, 1 & 1= 1。

举个例子 :

3 &5 即 00000011 & 00000101 = 00000001 ,所以 3 & 5的值为1。

0 人点赞