美文网首页编程题集锦
求幂、快速幂运算

求幂、快速幂运算

作者: szu_bee | 来源:发表于2017-07-11 15:30 被阅读50次

对一个给定的数计算乘幂。这一过程的参数是一个基数b和一个正整数的指数n,过程计算出b ^ n。
一种方式是通过下面这个递归定义:

b ^ n = b * b ^ (n - 1)
b ^ 0 = 1

线性递归:
【时间复杂度:O(n),空间复杂度:O(n)】

(define (expt b n)
  (if (= n 0) 1
      (* b (expt b (- n 1)))))

线性迭代:
【时间复杂度:O(n),空间复杂度:O(1)】

(define (expt b n)
  (define (expt-iter n product)
    (if (= n 0) product
        (expt-iter (- n 1) (* product b))))

  (expt-iter n 1))

快速幂运算
我们可以通过连续求平方,以更少的步骤完成乘幂运算。
例如,不是采用这种方式计算b ^ 8:

b * (b * (b * (b * (b * (b * (b * b)))))) 

而是用三次乘法算出它来:

b ^ 2 = b * b
b ^ 4 = b ^ 2 * b ^ 2
b ^ 8 = b ^ 4 * b ^ 4

如果采用下面规则,我们就可以借助于连续求平方,去完成一般的乘幂运算:

b ^ n = (b ^ (n / 2)) ^ 2     若n是偶数
b ^ n = b * b ^ (n - 1)       若n是奇数

递归算法:
【时间复杂度:O(log n),空间复杂度:O(log n)】

(define (fast-expt b n)
  (define (even?) (= (remainder n 2) 0))
  (define (square x) (* x x))

  (cond ((= n 0) 1)
        ((even?) (square (fast-expt b (/ n 2))))
        (else (* b (fast-expt b (- n 1))))))

迭代算法:
【利用关系(b ^ (n / 2)) ^ 2 = (b ^ 2) ^ (n / 2)
另外维持一个附加的状态变量ret,并定义好状态变换,使得从一个状态转到另一状态时乘积a * (b ^ n)保持不变。
重要思想:定义一个不变量,要求它在状态之间保持不变】
【时间复杂度:O(log n),空间复杂度:O(1)】

(define (even? x) (= (remainder x 2) 0))    // racket实现了此函数,可省略
(define (square x) (* x x))

(define (fast-expt b n)
  (define (fei b n ret)
    (cond ((= n 0) ret)
          ((even? n) (fei (square b)
                          (/ n 2)
                          ret))
          (else (fei b
                     (- n 1)
                     (* ret b)))))

  (fei b n 1))
// 测试
(fast-expt 2 4)
(fast-expt 3 3)
(fast-expt 4 5)
(fast-expt 5 3)
// 输出
16
27
1024
125

应用
通过反复做加法的方式求乘积,只用对数(O(log n))的计算步数。

a * b = (a * (b / 2)) * 2
a * b = a + a * (b - 1)

【原理与快速幂运算求乘幂类似】

递归

(define (double x) (* x 2))
(define (halve x) (/ x 2))

(define (multi a b)
  (cond ((= b 0) 0)
        ((even? b) (double (multi a
                                  (halve b))))
        (else (+ a
                 (multi a (- b 1))))))

迭代

(define (double x) (* x 2))
(define (halve x) (/ x 2))

(define (mul a b)
  (define (mul-iter a b ret)
    (cond ((= b 0) ret)
          ((even? b) (mul-iter (double a)
                               (halve b)
                               ret))
          (else (+ a
                   (mul-iter a
                             (- b 1)
                             (* a ret))))))

  (mul-iter a b 0))

------------------------------------
// else 语句里面的写法可替换成:
(else (mul-iter a
                (- b 1)
                (+ a ret)))
// 测试
(mul 2 4)
(mul 5 20)
(mul 33 88)
(mul 99 11)
// 输出
8
100
2904
1089

相关文章

  • 快速幂

    常规求幂 快速求幂(一般) 快速求幂 (递归) 快速求幂(位运算) 快速求幂(位运算,更简洁)

  • 求幂、快速幂运算

    对一个给定的数计算乘幂。这一过程的参数是一个基数b和一个正整数的指数n,过程计算出b ^ n。一种方式是通过下面这...

  • 二分求幂

    二分求幂法是快速计算形如 的求幂运算的方法。朴素计算 的方式是将 连乘 次,代码如下: 这需要计算 次,...

  • Python 运算符

    一. 运算符 +, -, *, /, **(幂运算), < , >, !=,<=, >=, ==, //(求余的整...

  • 快速幂

    今天的内容是快速幂,是编程中求幂的得力能手,一定要背下来哦。注意:本篇对三目运算符做了一定的介绍。如果已对三目运算...

  • python基础-运算符

    算术运算符:(7种) 、 - 、 * 、 / 、 % 、 // 、**加、减、乘、除、求余数、求商整数、求幂运算赋...

  • 模板 | 整数快速幂 & 快速幂取模

    快速幂: 所谓的快速幂,其目的是为了快速求幂,将时间复杂度从朴素算法的降到。 假如现在要求 ,按照朴素算法,就是将...

  • 一张图解决Python运算符优先级问题

    Python运算优先级金字塔图解: 特别注意:幂运算和正负号问题 如果幂运算左侧有负号,幂运算优先级高;如果幂运算...

  • 快速幂,矩阵快速幂

    快速幂:复杂度为logn,比普通的n快了很多了. 原理 : 实现代码如下:(位运算,简单,简洁) 矩阵快速幂: 所...

  • 几个数论小算法

    快速幂 个人感觉用的不多 快速幂取模 有时候幂运算所得到结果过大,导致溢出。而我们只想得到最后取模的结果。原理 ...

网友评论

    本文标题:求幂、快速幂运算

    本文链接:https://www.haomeiwen.com/subject/qlhmhxtx.html