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 感悟:
  我这周做题发现,数学技巧在解决问题中起着很重要的作用,能够简化代码,降低时间复杂度,许多看似困难、复杂的问题,只要运用数学方法,很快就能解决;此外,我操作符和递归方面比较弱,对右移、左移运算符等比较陌生,有待加强。

 

posted @ 2022-01-23 11:49  梦千幽  阅读(43)  评论(0)    收藏  举报