LeetCode 面试题 08.05. 递归乘法——快速幂算法

307 阅读1分钟

LeetCode 面试题 08.05. 递归乘法

解法一

题解:递归

class Solution {
public:
    int multiply(int A, int B) {
        if (A == 0 || B == 0) return 0;
        // if (A == 1) return B;
        if(A>B) swap(A, B);
        return multiply(A-1, B) + B;
    }
};

要点:为了避免递归调用太多,造成栈溢出,当A大于B时,交换A和B的值。

解法二

题解:快速幂

  1. 迭代
func multiply(A int, B int) int {
class Solution {
    public:
    int multiply(int A, int b) {
            int ret=0;
            unsigned int a = A;
            while(b>0){
                if((b&1)==1){
                    ret+=a;
                }
                 a+=a;
                 b>>=1;
                }
        return ret;
        }
    };
}

要点:用unsigned int是为了避免溢出问题。

  1. 递归
class Solution {
public:
    int multiply(int a, int b) {
        if(b == 0) return 0;
        if(b % 2 == 0) return (multiply(a, b>>1) << 1);
        else return (a + multiply(a, b-1));
    }
};

快速幂

快速幂基于二分的思想,常被称为二分幂。快速幂基于两个事实:

(1)若b为奇数,则a^b = a * a^(b-1);

(2)若b为偶数,则a^b = a^(b/2) * a^(b/2)。

迭代实现

思路

对a来说,如果把b写成二进制,b就可以写成若干二次幂的和。例如13的二进制是1101,3,2,0号位都是1,那么就可以得到 13= 2^3 +2^2 +2^0= 8+4+1,所以 a^13= a^(8+4+1)= a^8 * a^4 * a^1。

因此可得快速幂迭代写法的一般思路:

①初始化令ret=1,存放累积的结果。

②判断b的二进制末尾是否为1 (也就是判断b是否为奇数),如果是,则令ret乘上a的值。

③令a平方,并将b右移一位(也就是将b除以2)。

④只要b大于0,就返回②。

代码

int fastPower(int a, int b)
{
    int ret = 1;
    while (b)
    {
        if (b % 2 == 1) // 如果b是奇数,需要将ret先乘a,其他操作与b为偶数的情况一样
            ret *= a;
        a *= a;
        b >>= 1;
    }
    return ret;
}

递归实现

思路

①当b是奇数的时候,a= a^(b−1) ∗a,然后b--。

②当b是偶数的时候,a= a^(b/2) ∗a^(b/2),然后b>>=1

③当b==0的时候,a=1,这也是最后递归的出口。

代码

int fastPower(int a, int b)
{
    if (b == 0) return 1;
    int ret = 0;
    if (b & 1)
    {
        ret = fastPower(a, b/2) * fastPower(a, b/2);
        return ret;
    }
    else
    {
        return (a * fastPower(a, b - 1));
    }
}