f(n) = f(n -1) + f(n-2)矩阵快速幂

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010916338/article/details/86239565

显然是求斐波那契数列的函数,1、1、2、3、5、8、13、21、34、……

首先想到的是递归:

    public static int F(int number){
        if (number == 1 || number == 2){
            return 1;
        }
        return F(number - 1) + F(number - 2);
    }

但是,最好不用递归,不到万不得已不用递归。

上面一段代码性能极差,当给定参数number=100时,已经循环不动。

=================================================================================

\because f(n)=1\cdot f(n-1)+1\cdot f(n-2)……………………①

\because f(n-1)=1\cdot f(n-1)+0\cdot f(n-2)………………②

\Rightarrow \begin{bmatrix} f(n)\\ f(n-1) \end{bmatrix}=\begin{bmatrix} 1 &1 \\ 1& 0 \end{bmatrix}\begin{bmatrix} f(n-1)\\ f(n-2) \end{bmatrix}

\Rightarrow \begin{bmatrix} f(n)\\ f(n-1) \end{bmatrix}=\begin{bmatrix} 1 &1 \\ 1& 0 \end{bmatrix}^{n-2} \begin{bmatrix} f(2)\\ f(1) \end{bmatrix}

于是只要求得\begin{bmatrix} 1 &1 \\ 1& 0 \end{bmatrix}^{n-2}即可。

=================================================================================

扫描二维码关注公众号,回复: 4926004 查看本文章

而类似求x^n还可以简化(快速幂)

例如:

X^{19}=X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X\cdot X时间复杂度是n=19

X^{19}={({({(X^2)}^2)}^2)}^2\cdot X^3时间复杂度n=5,平方后的数都可以看做是整体,全部下来只需做5次乘法。

X^{19}的伪代码如下:

初始化res = X,tmp = 1,n = 19(二进制10011)

(1)判断   n & 1   (按位与,值为1,得出n为奇数)

tmp = tmp * res = 1 * X = X

res = res * res = X * X = X^2

n = n >> 1  (二进制1001,n向右移动一位,相当于除以2)

(2)判断   n & 1   (值为1)

tmp = tmp * res = 1 * X^2X^3

res = res * res = X^2\cdot X^2=X^4

n = n >> 1  (二进制100)

(3)判断   n & 1   (值为0,得出n为偶数)

res = res * res = X^4\cdot X^4=X^8

n = n >> 1  (二进制10)

(4)判断   n & 1   (值为0,得出n为偶数)

res = res * res = X^8\cdot X^8=X^{16}

n = n >> 1  (二进制1)

(5)判断   n & 1   (值为1,得出n为奇数数)

tmp = tmp * res = X^3 \cdot X^{16}=X^{19}

res = res * res = X^{16}\cdot X^{16}=X^{32}

return tmp

=================================================================================

Java代码实现如下:

//定义两个矩阵相乘
//防止结果溢出,使用BigInteger类型
public static BigInteger[][] matrixProduct(BigInteger[][] arrLeft, BigInteger[][] arrRight){
        BigInteger result[][] = {{new BigInteger("0"),new BigInteger("0")},{new BigInteger("0"),new BigInteger("0")}};
        for (int i = 0; i <= 1; i++){
            for (int j = 0; j <= 1; j++){
                result[i][j] =  arrLeft[i][0].multiply(arrRight[0][j]).add(arrLeft[i][1].multiply(arrRight[1][j]));
            }
        }
        return result;
    }



//定义矩阵的平方
public static BigInteger[][] matrixProductSquare(BigInteger [][] arrIn){
        BigInteger result[][] = {{new BigInteger("0"),new BigInteger("0")},{new BigInteger("0"),new BigInteger("0")}};

        BigInteger [][] arrLeft = arrIn;
        BigInteger [][] arrRight = arrIn;

        if (arrIn != null){
            for (int i = 0; i <= 1; i++){
                for (int j = 0; j <= 1; j++){
                    result[i][j] =  arrLeft[i][0].multiply(arrRight[0][j]).add(arrLeft[i][1].multiply(arrRight[1][j]));
                }
            }
        }


   //定义矩阵快速幂方法
   public static BigInteger[][] matrixFastPower(BigInteger[][] arrIn, int n){
        BigInteger result[][] = arrIn;
        BigInteger tmp[][] = {{new BigInteger("1"),new BigInteger("0")},{new BigInteger("0"),new BigInteger("1")}};//初始值为单位阵
        while (n != 0){
            if ((n & 1) == 1){
                tmp = matrixProduct(tmp.clone(), result);//参与计算的矩阵又赋值给原来的矩阵,需要深拷贝
                result = matrixProductSquare(result.clone());
                n = n >> 1;
            }else {
                result = matrixProductSquare(result.clone());
                n = n>>1;
            }
        }
        return tmp;
    }


    //经测试,100万次方需要3秒钟,1000万次方需要58秒钟
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        BigInteger arrIn[][] = {{new BigInteger("1"),new BigInteger("1")},{new BigInteger("1"),new BigInteger("0")}};
        BigInteger res[][] = matrixFastPower(arrIn, 10000000);
        for (int i = 0; i <= 1; i++){
            for (int j = 0; j <= 1; j++){
                System.out.println(res[i][j].toString());
            }
        }
        System.out.println((System.currentTimeMillis() - start) / 1000);
    }

f(10000000)运行结果如下(打印也要耗费时间)。

猜你喜欢

转载自blog.csdn.net/u010916338/article/details/86239565
今日推荐