1-23 周报
1 新学知识:
1.1 快速幂(计算乘方O(log n))
例如5的10次方,怎样算比较快?
(1)5*5…*5, 一步一步算。但是这样太慢了,可以拆分问题。
(2)先算5的5次方,即5*5*5*5*5,再算它的平方,共进行了5次乘法。
(3)先算5*5得25,则5的5次方为25*25*5,再算它的平方,共进行了4次乘法。
递归:
#include <iostream>
using namespace std;
int fun(int a, int b)
{
if (b == 0)
return 1;
else if (b%2 == 1)
return fun(a,b - 1)*a;
else
{
int abs = fun(a,b / 2); //abs存在可以减少递归次数
return abs*abs;
}
}
int main()
{
int a,b;
cin>>a>>b;
cout<<fun(a,b)<<endl;
return 0;
}
非递归(函数):
int fun(int a, int b)
{
int ans = 1;
while(b)
{
if(b%2==1)
ans *= a;
a *= a;
b >>= 1; //n往右移一位
}
return ans;
}
1.2 整数分解为2的幂相加
递归:
#include <iostream>
using namespace std;
int fun(int n)
{
if (n == 1) return 1;
else if (n%2 == 1)
return fun(n - 1);
else
return fun(n - 1)+fun(n / 2);
}
int main()
{
int a,ans;
while(cin>>a)
{
ans=fun(a);
cout<<ans<<endl;
}
return 0;
}
非递归:
#include <iostream>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int array[n+1];
for(int i=0;i<=n;i++)
array[i]=1; //初始化为1,表示n拆分为n个1,这一种拆分方法
int k=2;
while(k<=n)
{
for(int j = k;j<=n;j++)//通过将1,合并为2的幂,得到的新的方法。
array[j]+=array[j-k]; //原有的方法个数,加上新的拆分方法个数
k*=2;
}
cout<<array[n]<<endl;
}
return 0;
}
1.3 计算二进制中1的个数
#include <iostream>
using namespace std;
int main()
{
int k,ans=0;
ans>>k;
while(k)
{
k&=k-1;
ans++;
}
cout<<ans<<endl;
return 0;
}
(1)k-1一个二进制的数减1,就是将这个二进制最右边的那个1变成0,然后它后边的所有位置都变成1~ 举例:0011 0100,减1(n-1)后变成:0011 0011。
(2)k&=(k-1),并操作就会将有0的位置都变成0,上面的例子的结果就是0011 0000,然后再赋值给n,这时n就去掉了一个1,或者叫做计数了一个1。以此类推,就可以得到1的个数。
1.4 更相减损术(求最大公约数)
(1)任意给定两个正整数;判断它们是否均为偶数。若是,则用2约分。
(2)两数相减取绝对值,接着把所得的差与较小的数相减,并取绝对值。继续这个步骤,直到两数相等。则第一步中约掉的若干个2的积与第二步中该数的乘积就是所求的最大公约数。
非递归形式:
#include <iostream>
using namespace std;
int main()
{
int a,b;
cin>>a>>b;
while(a != b)
{
if(a > b)
a-=b;
else
b-=a;
}
cout<<a<<endl;
return 0;
}
递归形式:
#include <iostream>
using namespace std;
int fun(int a,int b)
{
if(a == b)
return a;
else if(a > b)
a-=b;
else
b-=a;
return fun(a,b);
}
int main()
{
int a,b;
cin>>a>>b;
cout<<fun(a,b)<<endl;
return 0;
}
此外,还了解到了一个以前不知道的代码写法:用if(a & 1)代替if(a%2 == 1)。
2 感悟:
我这周做题发现,数学技巧在解决问题中起着很重要的作用,能够简化代码,降低时间复杂度,许多看似困难、复杂的问题,只要运用数学方法,很快就能解决;此外,我操作符和递归方面比较弱,对右移、左移运算符等比较陌生,有待加强。