统计整数的二进制展开中数位1的个数
这种下面有两种解法。
一种是最普通的把整数转换成二进制(转换成几进制就除以几,用%来),每个位都进行一次判断,
是就加1并继续转换,若不是就不加1直接继续转换。
代码:
#include <iostream>
using namespace std;
int main()
{
unsigned num, count = 0;
cin>>num;
while(num)
{
if(num % 2 == 1)
{
count++;
}
num /= 2;
}
cout<<count<<endl;
return 0;
}
这种解法的时间复杂度为O(n),其实也还好。
另外一种解法是利用位运算来做的,时间复杂度变成了O(logn),更好
这里只写了被调用的函数,没写主函数
int countOnes(unsigned int)
{
int ones = 0;
while(0 < n)
{
ones += (1 & n);//检查最低位,若为1则计数
n >>= 1;//右移一位
}
return ones;
}
这里是利用位运算符 &(&运算符左右都为1结果才为1) 来做的,比如441,它的二进制是110111001,1
的二进制与441的二进制对齐(即补全前面的0)则是000000001,1和441的二进制进行&后,变成
000000001,因为只有最后一个位都是1(如果有一个为0,则结果为0),也就求出二进制最后一位是1,
所以ones就加1,然后进行移位运算(移位运算符的作用可以百度下,很简单),把n的二进制的位数变
成8个,这样原本倒数第二位的二进制数就变成了最后一个,相同的这样进行处理,直到n等于0,因为
每次右移一位,就相当于除以二(左移一位相当于乘以2),所以2^x = n;x = logn,求出的logn就是时
间复杂度
斐波那契数列的计算
博弈的题,有时候会用到斐波那契数列,比如取石子的题
如果采用二分递归的方式来求数列,那么有很多重复的项要计算,
斐波那契数的二分递归的定义
n n<=1
fib(n) = {
fib(n-1) + fib(n-2) n>=2
每个fib(i)都会计算多次,这样不仅时间复杂度变大了,为O(2^n),所以数就算不大,效率也低,空
间复杂度也同样变大了
而如果采用迭代形式进行运算(也可以进行线性递归来求,时间复杂度虽然是降低了,但是空间复杂度
仍不是常数级,线性递归这里不讲。关于二分递归和线性递归的区别,可以查阅相关资料)。
采用迭代的形式来求,
int num[50] = {0}
unsigned fib(int n)
{
int i = 0;
unsigned f = 1, g = 0;
while(0 < n--)
{
g += f;
f = g-f;
num[i++] = g;//每一个数都存在数组里
}
}
这样的话,每次都只是记录了当前的一对斐波那契数,可以直观的看出,时间复杂度为0(n),而空间复
杂度也变成了常数级O(1)(所占用的内存空间是常数)
这样不管是时间还是空间都有很大的优化。
总结
最新推荐文章于 2020-08-27 17:20:20 发布