力扣看题,发现一道简单题,判断一个数是否是4的次幂
写了这个之后,发现他们都是直接除法,或者用上了log.
不过这题的tag既然是位运算,大概都没有符合题意把XD
解题思路
- 首先不会是负数,排除掉 , 然后4的指数和2的指数,区别就是4的指数是特殊的2的指数 , 2的指数只有一个bit,然后既然只有一个bit,只通过前置bit数量可以知道数值的大小,
- 然后如果前置bit为0的个数是奇数个,就是4的指数 , 前置零的方法在integer里面有,这里改造一下可以用到这道题里面.
- 原方法是舍弃后面,只取最高位 , 你把他的移位-1(就是纯1数) , &一下看他有没有为1的bit位, 有的话加上之前的bit位说明bit位个数大于一个了,直接返回false就行(再解释一下就是例如n >= half1那个判断,你知道他前16位是一定有个1的 , 此时你用 & 一下 (1<<16) - 1 , 说明后面16位也有一个1 , 那么bit位1的个数至少两个 , 是不符合4的次幂的 , 直接pass )
int32哥bit位,而且2和4的次幂只有一个bit , 天然的适合用二分法来解
代码
private boolean isPowerOfFour_try02(int n) {
if (n <= 0) {
// 如果是负数 , 那么首位是1 , 没有前置0 , 如果是0就是32位, 所以特殊处理 .
// 这里场景是4的指数 , 小于等于0可以pass了,不会是负数
return false;
}
// 这里采用的是二分法的思想 , 就和那个10次以内才出1000以内的任何数字一样 , 每次把key缩小一倍去判断 . 找到第一个非0位置 .
int leadTemp = 31;
int nCopy = n;
if (n >= 0x10000) {
leadTemp -= 16;
n >>>= 16;
}
if (n >= 0x100) {
leadTemp -= 8;
n >>>= 8;
}
if (n >= 0x10) {
leadTemp -= 4;
n >>>= 4;
}
if (n >= 4) {
leadTemp -= 2;
n >>>= 2;
}
int leadZero = leadTemp - (n >>> 1);
return leadZero % 2 == 1 && (nCopy & ((1 << (31 - leadZero)) - 1)) == 0;
}
解法2
补码中 , 负数的补码有个规律, 就是先把一个正数中所有位取反 , 然后再+1 .
实际上这样就可以用 i & -i来获取某个数只保留最右侧一个bit为1的数 , 如果这个数等于本身说明本身只有一个bit .
例如 100 , 负数的补码就是 若干个1然后接着100 .
所以2的指数可以用 n > 0 && n == (n & -n) 判断 , 再加上首位0的个数是奇数 . && Integer.numberOfLeadingZeros(n) % 2 == 1.
方法就是
{
return n > 0 && Integer.numberOfLeadingZeros(n) % 2 == 1 && n == (n & -n);
}