如何判断2的n次方?用四种方式来扒一扒。

文章目录

    • 写在前面:
    • 方式一:用while循环反复除
      • 这种方式肯定是最好想到的,反复除,判断余数是否为零。
    • 方式二:用while循环反复乘
      • 反复乘,大了返回false,小了继续乘,等于就true。
    • 方式三:(x != 0) && ((x & -x) == x);
      • 原码,反码,补码。
      • 了解了这些,我们可以看一下这段代码(x != 0) && ((x & -x) == x);是什么含义
        • a.首先我们判断x是否为0,为0直接返回false
        • b.我们还是拿8来说
        • c.拿7看就不成立了
    • 方式四:((x != 0) && ((x & x - 1) == 0));
      •        这个和上面的方式异曲同工
    • 测试效率
    • 我最想说的是(等下我是不是跑题了,滑稽.jpg)
    • 总结:

写在前面:

      关于求2的n次方问题一直是一个比较基础,但是常常拿来考察的问题,下面我列举了4种方法来判断2的n次幂,并简单测一下各种方法的效率。今天咱们就来好好扒一扒这2的n次方判断问题。

方式一:用while循环反复除

这种方式肯定是最好想到的,反复除,判断余数是否为零。

    public static boolean check2(int x) {
        if (x < 1) {
            return false;
        }
        int xx = x;//定义xx保存x的值,后面用来判断余数是否为零
        while (x >= 2) {
            xx = x;
            x = x / 2;
            if (xx - x * 2 != 0) {
                return false;
            }
        }
        return true;
    }

方式二:用while循环反复乘

反复乘,大了返回false,小了继续乘,等于就true。

   public static boolean check3(int x) {
        int flag = 1;//被乘的初始值设置为1
        while (true) {
            if (flag < x) {//小了继续乘
                flag *= 2;
            } else if (flag == x) {//等于就true
                return true;
            } else {//大了返回false
                return false;
            }
        }
    }

方式三:(x != 0) && ((x & -x) == x);

原码,反码,补码。

      首先我们要了解一下什么是原码,反码,补码。
      打个比方,拿8来说,求一下他的4位二进制
如何判断2的n次方?用四种方式来扒一扒。_第1张图片

      原码:正数符号位为0,数值化为2进制

      反码:符号位不变,数值位取反

      补码:原码符号位置不变,数值位取反末位加一或者是反码直接末位加一(电脑中的数值运算都是用补码表示)

了解了这些,我们可以看一下这段代码(x != 0) && ((x & -x) == x);是什么含义

a.首先我们判断x是否为0,为0直接返回false
  public static boolean check1(int x) {
        return (x != 0) && ((x & -x) == x);
  }
b.我们还是拿8来说

如何判断2的n次方?用四种方式来扒一扒。_第2张图片

      我们可以看到8的补码和-8的补码进行&运算(同一为一),得到的结果刚好就是8的本身。即(x & -x) == x。

      而且我们可以看到,当判断的x为-8时相&的结论是与-8本身不一样的,这就很好的减少了我们判断负数的工作

c.拿7看就不成立了

如何判断2的n次方?用四种方式来扒一扒。_第3张图片

方式四:((x != 0) && ((x & x - 1) == 0));

       这个和上面的方式异曲同工

如何判断2的n次方?用四种方式来扒一扒。_第4张图片

测试效率

 public static void main(String[] args) {
        long timeA1 = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            if (check2(i)) {
                System.out.print(i);
            }
        }
        long timeA2 = System.currentTimeMillis();
        System.out.println("方式一:" + (timeA2 - timeA1));

        long timeB1 = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            if (check3(i)) {
                System.out.print(i);
            }
        }
        long timeB2 = System.currentTimeMillis();
        System.out.println("方式二:" + (timeB2 - timeB1));

        long timeC1 = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            if (check1(i)) {
                System.out.print(i);
            }
        }
        long timeC2 = System.currentTimeMillis();
        System.out.println("方式三:" + (timeC2 - timeC1));


        long timeD1 = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            if (check11(i)) {
                System.out.print(i);
            }
        }
        long timeD2 = System.currentTimeMillis();
        System.out.println("方式四:" + (timeD2 - timeD1));
    }

如何判断2的n次方?用四种方式来扒一扒。_第5张图片

基本上来说方式三,四的执行效率差不多,大约都是方式一的三到四倍,方式二的七到八倍。

我最想说的是(等下我是不是跑题了,滑稽.jpg)

      在计算机的设计中是只有加法器没有减法器的,因为其实减法都是可以用加法来实现的,如同7-3=4可以写成7+(-3)=4,这就减少了计算机还要设计减法器的麻烦。而为了计算机实现的简便,就出现了补码的概念。举个例子

如何判断2的n次方?用四种方式来扒一扒。_第6张图片

可以看到使用补码相加直接得到了0 0100,转换成十进制就是4,对计算机来说这就很方便了,减少了设计减法器,感觉干掉了一半的工作量。

总结:

      要是再次面对这个问题时,可以和面试官含情脉脉娓娓道来,一个2的n次方聊上十几二十分钟也不是不可以!滑稽.jpg。毕竟基础的东西还是很重要的,这种问题往往能反映出一个人的基础是否扎实

如果喜欢或者对你有帮助,老铁记得点个赞哦。
如何判断2的n次方?用四种方式来扒一扒。_第7张图片

你可能感兴趣的:(算法设计与分析,java,补码,原码,反码,算法,编程语言,补码)