快速求幂运算

目录

第六关 快速求幂

任务描述

编程要求

测试说明

基础知识

原理

 实现

1. 递归

2. 循环


来自实训十 选做题

第六关 快速求幂

任务描述

本关任务:利用快速幂算法实现函数long long quickPow(int n, int k), 计算原理如下,其中int(x)表示不超过x的最大整数:

当k为偶数时, nk=(nk/2)2

当k为奇数时, nk=n(nint(k/2))2

编程要求

根据提示,在右侧编辑器补充代码,输入非负整数n和k,输出n的k次方

测试说明

平台会对你编写的代码进行测试:

测试输入:2 3 预期输出: 8

基础知识

1. int()是将向下取整的函数。

2. 偶数在二进制里面,最后一位为0,奇数则为1。 所以可以通过与1做 位与运算 判断奇偶数。 (num & 1) == 0 如果结果为true则为偶数,为false则为奇数。(num & 1)如果结果为true则为奇数,为false则为偶数。

3. 在c++中有双目移位运算符:<<(左移)和 >>(右移)。 移位运算符组成的 表达式 也属于 算术表达式 ,其值为算术值。语法格式:需要移位的数字>>移位的次数n

无符号:左移运算按二进制形式把所有数字向左移动相应的n位数,高位舍弃,低位的空位补0,相当于乘以2的n次方。比如8的二进制表示是00000000 00000000 00000000 00001000,左移2位(8<<2) 得到00000000 00000000 00000000 00100000,转换为十进制是8\times 2^2右移运算按二进制形式把所有数字向右移动相应的n位数,低位舍弃,高位的空位补0,相当于除以2的n次方。比如8的二进制表示是00000000 00000000 00000000 00001000,右移2位(8>>2) 得到00000000 00000000 00000000 00000010,转换为十进制是8\div 2^2

有符号:如果左移有符号的数字,以至于符号位受影响,则结果是不确定的。右移按二进制形式把所有数字向右移动相应的位数,低位舍弃,正数高位的空位补0;负数高位的空位补1

原理

假设要求x^n,如果n = 2^k,那么:x^n = x^{2^k} = \underbrace{(((x^2)^2)^{2\cdots \cdots })^2}_{k}

这样只要做k次平方运算就能解决,时间复杂度就从O(n)下降到log(n)。

只要幂运算的幂可以写成包含2^k的形式,就可以用上面的方法降低时间复杂度,所以我们可以将任意的实数n改写有限个2^k的形式的相加。比如x^{22} = x^{16} x^{4} x^2,可以分别对x^{16}x^4以及x^2使用上述方法快速计算结果,最后三者相乘就可以了;比如x^{21} = x^{16} x^4 x,可以对x^{16}x^4使用上述方法快速计算结果,两者相乘再乘以x就可以了。

 实现

1. 递归

#include <iostream>
#include <cmath>
using namespace std;


long long quickPow(long long a,long long b){
    //特殊条件
    if (a==1) return 1;
    //递归
	if (b==0) return 1;
    if (b%2==1) return a * pow(quickPow(a, int(b/2)), 2);
    if (b%2==0) return pow(quickPow(a, b/2),2);
    }


int main() 
{
  int n, k;
  cin >> n >> k; 
  cout << quickPow(n, k);
  return 0;
}

2. 循环

 可读性较强的版本

#include <iostream>
#include <cmath>
using namespace std;


long long quickPow(long long a,long long b){
    long long res = 1;
    while (b>0) {
        //如果指数是偶数
        if (b % 2 == 0) {
            b /= 2;
            a = a*a;
        }
        //如果指数是奇数
        else {
            b--; //使得b变成偶数,加上后面b /= 2达到向下取整的目的
            res *= a; 
            b /= 2;
            a = a*a;
        }
    }
    return res;
}


int main() 
{
  int n, k;
  cin >> n >> k; 
  cout << quickPow(n, k);
  return 0;
}

较简洁的版本 

#include <iostream>
#include <cmath>
using namespace std;


long long quickPow(long long a,long long b){
    long long res = 1;
    while (b) {
        if (b & 1) res *= a;
        a = a*a;
        b >>= 1;
    }
    return res;
}


int main() 
{
  int n, k;
  cin >> n >> k; 
  cout << quickPow(n, k);
  return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值