题目:判断一个正整数num是否可表示为2的N次方。
对于这样一道题目,最简单的做法就是定义一个变量,并让其以2的n(n=0,1,2,3,...)次方递增,每次递增后与num比较,如果相等则返回true,直到递增到大于num,返回false。
/************************************************************************/
/*
判断一个正整数num是否为2的N次方(常规解法1)
算法时间复杂度为O(logN),空间复杂度为O(1)
*/
/************************************************************************/
bool Is2pow_1(unsigned int num) {
unsigned int temp = 1;
while(temp <= num) {
if (temp == num) {
return true;
}
temp = temp * 2;
}
return false;
}
以下解法2,可以在算法性能上有所提高。(位运算的性能高于乘法运算)
/************************************************************************/
/*
判断一个正整数num是否为2的N次方(常规解法2)
算法时间复杂度为O(logN),空间复杂度为O(1)
*/
/************************************************************************/
bool Is2pow_2(unsigned int num) {
unsigned int temp = 1;
while(temp <= num) {
if (temp == num) {
return true;
}
temp = temp << 1; // 位运算比乘法运算性能高,在一定程度提高性能
}
return false;
}
对于以上解法1和解法2,在本质上都是一样的,没有减少算法的时间复杂度。
下面的解法才是真正的算法优化,将时间复杂度降到了O(1)。
/************************************************************************/
/*
判断一个正整数num是否为2的N次方
基本思想:
十进制 二进制 N-1 N&N-1 是否为2的乘方
8 1000 111 0 是
16 10000 1111 0 是
32 100000 11111 0 是
100 1100100 1100011 1100000 否
算法时间复杂度为O(1),空间复杂度为O(1)
*/
/************************************************************************/
bool Is2pow(unsigned int num) {
if (num == 0){
return false;
}
return (num & (num-1)) == 0;
}
以上算法,主要是利用与运算进行性能的优化,根据于此,我们可以扩展出如下两个基本的题目:
扩展题目1:给定一个正整数num,求其二进制中"1"的个数。
扩展题目2:给定一个正整数num,求其二进制中"0"的个数。
以上扩展题目的程序代码如下:
/************************************************************************/
/*
计算一个正整数num转化为二进制后,"1"的个数。
基本思想:从右到左依次去除"1",并统计其个数。
算法的计算次数只与num的位数有关,与其大小无关。
算法时间复杂度为O(logN),空间复杂度为O(1)
*/
/************************************************************************/
unsigned int NumberofOne(unsigned int num) {
int count = 0;
while (num) {
num = num & (num-1);
count++;
}
return count;
}
/************************************************************************/
/*
计算一个正整数num转化为二进制后,"0"的个数。
基本思想:从右到左依次与1进行与操作,并统计其个数。
算法的计算次数只与num的位数有关,与其大小无关。
算法时间复杂度为O(logN),空间复杂度为O(1)
*/
/************************************************************************/
unsigned int NumberofZero(unsigned int num) {
int count = 0;
while (num) {
if ((num & 0x01) != 1){
count++;
}
num = num >> 1;
}
return count;
}