【算法&数据结构体系篇class26】:斐波那契数列 矩阵快速幂技巧 时间复杂度O(logN)

本文介绍了使用矩阵快速幂技巧优化斐波那契数列的计算,详细阐述了矩阵乘法在求解斐波那契数列中的应用,将时间复杂度降至O(logN)。此外,还探讨了类似斐波那契数列结构的递归优化方法,并列举了矩阵乘法在不同问题(如迈台阶问题、铺瓷砖问题、生牛问题)中的应用。最后提出了一种字符串匹配问题,寻找由0和1组成的字符串中,所有0字符左侧都有1紧邻的情况。

一、求斐波那契数列矩阵乘法的方法

1)斐波那契数列的线性求解(O(N))的方式非常好理解

2)同时利用线性代数,也可以改写出另一种表示

 | F(N) , F(N-1) | = | F(2), F(1) |  *  某个二阶矩阵的N-2次方

3)求出这个二阶矩阵,进而最快求出这个二阶矩阵的N-2次方

4)斐波那契数列 1 1 2 3 5 8 13.....其为fn = fn-1 + fn-2   最底层n-2 是二阶矩阵 n-2次方

    其二阶矩阵为   1   1    也就是[ [1,1] [1,0]  ]二维数组

                             1   0

 

二、类似斐波那契数列的递归优化

如果某个递归,除了初始项之外,具有如下的形式

F(N) = C1 * F(N) + C2 * F(N-1) + … + Ck * F(N-k) ( C1…Ck k都是常数)

并且这个递归的表达式是严格的、不随条件转移的

那么都存在类似斐波那契数列的优化,时间复杂度都能优化成O(logN)

 

先判断公式最底层阶数 i   fn =  fn-1...+ fn-i  依赖最低层的就是阶数 i阶
* 得到公式 :
* |fn,fn-1,fn-2..fn-i+1| (共i项)  =  |fi,fi-1,fi-2...1| (共i项) * 矩阵i*i 的 n-i次方

三、斐波那契数列矩阵乘法方式的实现

1.斐波那契数列   1,1,2,3,5,8,13....

f(n) = f(n-1) + f(n-2)    

2.迈台阶问题     1,2,3,5,8,13,21....

f(n) = f(n-1) + f(n-2) 

3.铺瓷砖问题     1,2,3,5,8,13,21....

f(n) = f(n-1) + f(n-2) 

4.生牛问题         1,2,3,4,6,9,13,19...

f(n) = f(n-1) + f(n-3) 
package class26;

/**
 * 斐波那契数列矩阵乘法方式的实现
 */
public class FibonacciProblem {

    /**
     * 斐波那契数列
     * @param n
     * @return
     */
    public static int f1(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2) {
            return 1;
        }
        return f1(n - 1) + f1(n - 2);
    }

    public static int f2(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2) {
            return 1;
        }
        int res = 1;
        int pre = 1;
        int tmp = 0;
        for (int i = 3; i <= n; i++) {
            tmp = res;
            res = res + pre;
            pre = tmp;
        }
        return res;
    }


    /**
     * 总结一个 递推公式
     * 斐波那契数列 : f(n) = f(n-1) + f(n-2)  最底层n-2 2阶  转换成矩阵乘法 降低时间复杂度
     * |f(n),f(n-1)| = |f(2),f(1)| * 矩阵[[1,1],[1,0]]的n-2次方
     *
     * 其他同类型的固化公式: fn = 6*f(n-1) + 3* f(n-5) 最底层n-5 5阶 系数不影响公式 只影响矩阵统计
     * |fn,fn-1,fn-2,fn-3,fn-4| = |f5,f4,f3,f2,f1| * 矩阵5*5 的 n-5次方
     *
     * 所以就是 先判断公式最底层阶数 i
     * 得到公式 :
     * |fn,fn-1,fn-2..fn-i+1| (共i项)  =  |fi,fi-1,fi-2...1| (共i项) * 矩阵i*i 的 n-i次方
     *
     * @param n
     * @return
     */
    // O(logN) 矩阵乘法方式的实现
    public static int f3(int n) {
        //边界判断 小于1 无效返回0
        if(n < 1) return 0;
        //初始1 2 首两个都是1
        if(n == 1 || n ==2) return 1;


        //因为斐波那契数列公式是 f(n) = f(n-1) + f(n-2) 依赖前2个 固定的一个公式 可以转换成
        //|f(n) , f(n-1)|  =  |f(2) , f(1)| * 某个固定二阶矩阵的N-2次方  针对斐波那契数列
        //这个固定二阶是因为依赖的最前面n-2  所有是一个二阶矩阵 也就是2*2二维数组   假设其他公式数列是到 n-3 那就是三阶数组3*3
        //根据公式推算 这个二阶矩阵是[[1,1][1,0]]
        //已知斐波那契数列  1,1,2,3,5,8....
        //|F3,F2| = |F2,F1| * |A|矩阵
        //|F4,F3| = |F3,F2| * |A|矩阵
        //|F5,F4| = |F4,F3| * |A|矩阵...
        //|FN,FN-1| = |FN-1,FN-2| * |A|矩阵

        //进行推算 |F2,F1| = |1,1|  |F3,F2| = |2,1|  假设|[a,b][cd]|矩阵
        //根据矩阵计算方式 得到  |F3,F2| = |F2*a + F1*c , F2*b + F1*d| =>  F3=2= a+c  F2=1= b + d 还需要一个等式才能算出a,b,c,d
        //|F4,F3| = |F3*a + F2*c , F3*b + F2*d|  =>  F4=3= 2a+c  F3=2= 2b + d       四个等式 最后得出 a=1,b=1,c=1,d=0
        //所以这个A矩阵就是
        // a b    =》   1 1
        // c d          1 0
        //根据每个等式都会包含前面一个值 比如|F4,F3| = |F3,F2| * 矩阵   F3 F2矩阵前面能通过 |F2,F1|* 矩阵得到
        //直到FN,FN-1 我们就能化解成 = |F2,F1| * |A|矩阵 n-2 次方
        //要得到FN 我们根据矩阵乘法运算   假设|A|矩阵 n-2 次方 得到一个值 [[a,b][c,d]]
        //那么|FN,FN-1| = |1,1| * [[a,b],[c,d]] = |1*a+1*c, 1*b+1*d|
        //求FN 就是 a+c  FN-1 就是 b+d
        // a就是   A矩阵位置[0][0]   c 就是 A矩阵位置[1][0] 两个位置值相加即可


        //根据分析 我们定义一个 矩阵a [[1,1][1,0] 求第n个值 那么就是 得到矩阵的 n-2次方的值
        int[][] base = {{1,1},{1,0}};

        //定义一个函数 将base 的n-2次方 值得到一个对应的矩阵数组  长度是一样的
        int[][] res = getN(base,n-2);
        return res[0][0] + res[1][0];
    }

    //获取这个二阶矩阵的 n次方   n = n-2 前面入参决定
    public static int[][] getN(int[][] base, int n){
        //这里有个技巧 如果快速运算 矩阵的n次方  我们需要利用二进制 将n次方转换成二进制数
        //然后起初 我们让矩阵等于1 *  base 1次方  2次方 4次方  8次方...   如果n =75 转换二进制 64 + 8 + 2 + 1 => 1001011
        //根据有1的位置 就需要成上次方 0 的位置就跳过  矩阵 n的75次方 =   1 *   矩阵1次方 * 2次方 8   64
        //矩阵值起始作为1     单位矩阵就可以作为1 因为其位置矩阵乘以任何数 都是=任何数  就是对角线为1 其他位置为0
        //[[1,0],[0,1]] 单位矩阵 * [[1,1],[1,0]]    矩阵乘法运算
        //
        // a b  *  e f
        // c d     g h
        //[[a,b][c,d]] * [[e,f][g,h]] = [a*e+b*g, a*f+b*h] [c*e+d*g, c*f+d*h]

        //定义一个结果数组矩阵  base是自身相乘  所以结果矩阵大小是一致的
        int row = base.length;
        int col = base[0].length;
        int[][] res = new int[row][col];

        //初始化矩阵 为单位矩阵 然后接着再去乘以 base矩阵  单位矩阵就是对角线为1 任何矩阵乘以单位矩阵都是自身
        //如果不初始化 一开始都是0 那乘以base结果都是0了
        for(int r = 0; r < row; r++){
            res[r][r] = 1; //因为矩阵是正方形的 所以就直接遍历行或列都可以 对角线赋值1
        }

        //base矩阵 n次方 我们利用n 的二进制位 如前面举例 n=75 => 1001011 最右侧开始位 与运算 1  判断位是否为1 为1 就表示要进行次方相乘 否则就无需相乘 跳过
        //定义一个辅助数组存放base 用来进行累乘
        int[][] temp = base;
        //遍历次方 每个往右移动一位 也就是次方数n 每次都除以2 递减
        for(; n != 0; n >>= 1){
            if((n & 1) != 0){
                //说明当前位是1, 需要进行temp相乘 刷新res 结果矩阵
                res = getPower(res,temp);
            }
            //接着会右移一位 次方也需要相乘起来  接着要把辅助的矩阵也同步要往高位得到新的值  也就是需要 自身*自身 比如来到 第2位 那么矩阵就是2次方值 3位就是3次方值
            temp = getPower(temp,temp);
        }
        return res;
    }

    //对两个矩阵进行相乘得到新矩阵值
    //
    // a b  *  e f
    // c d     g h
    //[[a,b][c,d]] * [[e,f][g,h]] = [a*e+b*g, a*f+b*h] [c*e+d*g, c*f+d*h]
    public static int[][] getPower(int[][] a, int[][] b){
        int rowa = a.length;        //矩阵a 行
        int colb = b[0].length;     //矩阵b  列
        int cola = a[0].length;     //矩阵a  列  根据矩阵运算的定义 a矩阵列 是跟b矩阵的行一致的 因为每次都是 某一行 a每列 要跟 b某一列 每行对应相乘 相加

        //定义一个结果矩阵 行数对应a矩阵的行   列数对应b矩阵的列
        int[][] res = new int[rowa][colb];
        for(int ra = 0 ; ra < rowa; ra++){
            for(int cb = 0; cb < colb; cb++){
                for(int ca = 0; ca < cola; ca++){
                    //这里ca 列 等同于 b矩阵的 行  ,所以可以共用
                    //矩阵0,0  就等于 a矩阵第0行  b矩阵第0列 每个位置一一相乘 再一一累加 a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0]...
                    //矩阵0,1       a矩阵第0行   b矩阵第1列...
                    //矩阵1,0              1           0...
                    res[ra][cb] += a[ra][ca] * b[ca][cb];
                }
            }
        }
        return res;
    }



    /**
     * 一个人可以一次往上迈1个台阶,也可以迈2个台阶
     *
     * 返回这个人迈上N级台阶的方法数
     *
     *
     * 用1*2的瓷砖,把N*2的区域填满
     *
     * 返回铺瓷砖的方法数
     *
     * 这两道都是一样的 1 2 3 5 8 13
     * @param n
     * @return
     */
    public static int s1(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2) {
            return n;
        }
        return s1(n - 1) + s1(n - 2);
    }

    public static int s2(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2) {
            return n;
        }
        int res = 2;
        int pre = 1;
        int tmp = 0;
        for (int i = 3; i <= n; i++) {
            tmp = res;
            res = res + pre;
            pre = tmp;
        }
        return res;
    }

    public static int s3(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2) {
            return n;
        }
        int[][] base = { { 1, 1 }, { 1, 0 } };
        int[][] res = getN(base, n - 2);
        return 2 * res[0][0] + res[1][0];
    }



    /**
     * 第一年农场有1只成熟的母牛A,往后的每年:
     *
     * 1)每一只成熟的母牛都会生一只母牛
     *
     * 2)每一只新出生的母牛都在出生的第三年成熟
     *
     * 3)每一只母牛永远不会死
     *
     * 返回N年后牛的数量
     *
     * 第一年只有1头母牛A
     * 第二年 母牛A 生了母牛B 母牛B第三年成熟 成熟年可以生牛 也就是过多三年 第五年
     * 第三年  母牛A 生了母牛C  A,B,C   C牛到第六年可以生牛
     * 第四年  A生了D  A,B,C,D
     * 第五年 A生了E B到第三年了 生F   A,B,C,D,E,F
     * 第六年 A生了G B生了H  C生了I  A B C D E F G H I...
     * 1  2  3  4  6  9  13...
     *
     * 得到 fn = fn-1 + fn-3 的关系式
     * @param n
     * @return
     */
    public static int c1(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2 || n == 3) {
            return n;
        }
        return c1(n - 1) + c1(n - 3);
    }

    public static int c2(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2 || n == 3) {
            return n;
        }
        int res = 3;
        int pre = 2;
        int prepre = 1;
        int tmp1 = 0;
        int tmp2 = 0;
        for (int i = 4; i <= n; i++) {
            tmp1 = res;
            tmp2 = pre;
            res = res + prepre;
            pre = tmp1;
            prepre = tmp2;
        }
        return res;
    }

    public static int c3(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2 || n == 3) {
            return n;
        }

        //矩阵也是通过类推得到 a矩阵 看关系fn = fn-1 + fn-3 最底依靠n-3 3阶
        //3阶 3*3矩阵  有以下关系类推得到矩阵的值

        /**
         *  1  2  3  4  6  9  13...
         * |4,3,2| = |3,2,1| * [[a,b,c],[d,e,f],[g,h,i]]
         * |6,4,3| = |4,3,2| * [[a,b,c],[d,e,f],[g,h,i]]
         * |9,6,4| = |6,4,3| * [[a,b,c],[d,e,f],[g,h,i]]
         *
         * 通过这里 可以得出9个公式 九个位置就能算出 矩阵就是
         *  1 1 0
         *  0 0 1
         *  1 0 0
         */
        int[][] base = {
                { 1, 1, 0 },
                { 0, 0, 1 },
                { 1, 0, 0 } };

        //i阶 次方就是 n-i   已知是3阶 所以就是n-3次方
        int[][] res = getN(base, n - 3);

        //返回fn 就是计算矩阵第一列 分别乘以 对应 |3 2 1| 初始的值
        return 3 * res[0][0] + 2 * res[1][0] + res[2][0];
    }



    public static void main(String[] args) {
        int n = 19;
        System.out.println(f1(n));
        System.out.println(f2(n));
        System.out.println(f3(n));
        System.out.println("===");

        System.out.println(s1(n));
        System.out.println(s2(n));
        System.out.println(s3(n));
        System.out.println("===");

        System.out.println(c1(n));
        System.out.println(c2(n));
        System.out.println(c3(n));
        System.out.println("===");

    }

}

四、给定一个数N,想象只由01两种字符,组成的所有长度为N的字符串,如果某个字符串,任何0字符的左边都有1紧挨着,认为这个字符串达标,返回有多少达标的字符串

package class26;

/**
 * 给定一个数N,想象只由0和1两种字符,组成的所有长度为N的字符串
 *
 * 如果某个字符串,任何0字符的左边都有1紧挨着,认为这个字符串达标
 *
 * 返回有多少达标的字符串
 *
 *
 * 推算:
 * N=1  1  1   不能为0,因为左边要有1
 * N=2  2  11 10             10  符合0左边有1
 * N=3  3  111 110 101      001 010不符合 每个0左边要有1
 * N=4  5  1111 1110 1101 1011 1010
 * N=5  8
 * N=6  13...
 * 得到是一个 fn = fn-1 + fn-2   数列    n=1||n=2 return n
 *
 * 尝试:
 * 假设一个函数fn  还有n个数要形成字符 那么在n-1前面 肯定是1  因为最左边的只能是1 不能为0
 * fn  范围就是  n,n-1,n-2...1 n个数
 * 从左到右
 * n位置如果选择了 1字符  那么后面n-1位置可以选择0或者1  fn递归依赖的就是 fn-1
 * n位置如果选择了 0字符   那么后面n-1位置肯定只能选1 不能选0 因为要确保每个0左边都有1  所以n-1位置固定  来到n-2位置 可以选择0或者1 所以fn 依赖 fn-2
 *
 * 得到 fn = fn-1 + fn-2 公式
 *
 *
 *
 * 与以下题目也是一个推算公式:
 * 用1*2的瓷砖,把N*2的区域填满
 * 返回铺瓷砖的方法数
 *
 * 带入我们矩阵乘法方式的实现 O(logN)    getNum3方法
 */
public class ZeroLeftOneStringNumber {

    public static int t(int n) {
        if (n == 0)
            return 0;
        if (n == 1 || n ==2)
            return n;

        return t(n - 1) + t(n - 2);
    }

    public static int getNum1(int n) {
        if (n < 1) {
            return 0;
        }
        return process(1, n);
    }

    public static int process(int i, int n) {
        if (i == n - 1) {
            return 2;
        }
        if (i == n) {
            return 1;
        }
        return process(i + 1, n) + process(i + 2, n);
    }

    public static int getNum2(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1) {
            return 1;
        }
        int pre = 1;
        int cur = 1;
        int tmp = 0;
        for (int i = 2; i < n + 1; i++) {
            tmp = cur;
            cur += pre;
            pre = tmp;
        }
        return cur;
    }

    /**
     * 总结一个 递推公式
     * 斐波那契数列 : f(n) = f(n-1) + f(n-2)  最底层n-2 2阶  转换成矩阵乘法 降低时间复杂度
     * |f(n),f(n-1)| = |f(2),f(1)| * 矩阵[[1,1],[1,0]]的n-2次方
     *
     * 其他同类型的固化公式: fn = 6*f(n-1) + 3* f(n-5) 最底层n-5 5阶 系数不影响公式 只影响矩阵统计
     * |fn,fn-1,fn-2,fn-3,fn-4| = |f5,f4,f3,f2,f1| * 矩阵5*5 的 n-5次方
     *
     * 所以就是 先判断公式最底层阶数 i
     * 得到公式 :
     * |fn,fn-1,fn-2..fn-i+1| (共i项)  =  |fi,fi-1,fi-2...1| (共i项) * 矩阵i*i 的 n-i次方
     *
     * @param n
     * @return
     */
    // O(logN) 矩阵乘法方式的实现
    public static int getNum3(int n) {
        //边界判断 小于1 无效返回0
        if(n < 1) return 0;
        //初始1 2 首两个都是1
        if(n == 1 || n ==2) return n;


        //变型斐波那契数列  1 2 3 5 8 13 21...
        //因为斐波那契数列公式是 f(n) = f(n-1) + f(n-2) 依赖前2个 固定的一个公式 可以转换成
        //|f(n) , f(n-1)|  =  |f(2) , f(1)| * 某个固定二阶矩阵的N-2次方  针对斐波那契数列
        //这个固定二阶是因为依赖的最前面n-2  所有是一个二阶矩阵 也就是2*2二维数组   假设其他公式数列是到 n-3 那就是三阶数组3*3
        //根据公式推算 这个二阶矩阵是[[1,1][1,0]]
        //已知斐波那契数列  1,1,2,3,5,8....
        //|F3,F2| = |F2,F1| * |A|矩阵
        //|F4,F3| = |F3,F2| * |A|矩阵
        //|F5,F4| = |F4,F3| * |A|矩阵...
        //|FN,FN-1| = |FN-1,FN-2| * |A|矩阵

        //进行推算 此时是个变形的数列  |F2,F1| = |2,1|  |F3,F2| = |3,2|  假设|[a,b][cd]|矩阵
        //根据矩阵计算方式 得到  |F3,F2| = |F2*a + F1*c , F2*b + F1*d| =>  F3=3= 2a+c  F2=2= 2b + d 还需要一个等式才能算出a,b,c,d
        //|F4,F3| = |F3*a + F2*c , F3*b + F2*d|  =>  F4=5= 3a+2c  F3=3= 3b + 2d       四个等式 最后得出 a=1,b=1,c=1,d=0
        //所以这个A矩阵就是
        // a b    =》   1 1
        // c d          1 0
        //根据每个等式都会包含前面一个值 比如|F4,F3| = |F3,F2| * 矩阵   F3 F2矩阵前面能通过 |F2,F1|* 矩阵得到
        //直到FN,FN-1 我们就能化解成 = |F2,F1| * |A|矩阵 n-2 次方
        //要得到FN 我们根据矩阵乘法运算   假设|A|矩阵 n-2 次方 得到一个值 [[a,b][c,d]]
        //那么|FN,FN-1| = |2,1| * [[a,b],[c,d]] = |2*a+1*c, 2*b+1*d|
        //求FN 就是 2a+c  FN-1 就是 2b+d
        // a就是   A矩阵位置[0][0]   c 就是 A矩阵位置[1][0] 2*res[0][0] + res[1][0];

        //根据分析 我们定义一个 矩阵a [[1,1][1,0] 求第n个值 那么就是 得到矩阵的 n-2次方的值
        int[][] base = {{1,1},{1,0}};

        //定义一个函数 将base 的n-2次方 值得到一个对应的矩阵数组  长度是一样的
        int[][] res = getN(base,n-2);
        return 2*res[0][0] + res[1][0];
    }

    //获取这个二阶矩阵的 n次方   n = n-2 前面入参决定
    public static int[][] getN(int[][] base, int n){
        //这里有个技巧 如果快速运算 矩阵的n次方  我们需要利用二进制 将n次方转换成二进制数
        //然后起初 我们让矩阵等于1 *  base 1次方  2次方 4次方  8次方...   如果n =75 转换二进制 64 + 8 + 2 + 1 => 1001011
        //根据有1的位置 就需要成上次方 0 的位置就跳过  矩阵 n的75次方 =   1 *   矩阵1次方 * 2次方 8   64
        //矩阵值起始作为1     单位矩阵就可以作为1 因为其位置矩阵乘以任何数 都是=任何数  就是对角线为1 其他位置为0
        //[[1,0],[0,1]] 单位矩阵 * [[1,1],[1,0]]    矩阵乘法运算
        //
        // a b  *  e f
        // c d     g h
        //[[a,b][c,d]] * [[e,f][g,h]] = [a*e+b*g, a*f+b*h] [c*e+d*g, c*f+d*h]

        //定义一个结果数组矩阵  base是自身相乘  所以结果矩阵大小是一致的
        int row = base.length;
        int col = base[0].length;
        int[][] res = new int[row][col];

        //初始化矩阵 为单位矩阵 然后接着再去乘以 base矩阵  单位矩阵就是对角线为1 任何矩阵乘以单位矩阵都是自身
        //如果不初始化 一开始都是0 那乘以base结果都是0了
        for(int r = 0; r < row; r++){
            res[r][r] = 1; //因为矩阵是正方形的 所以就直接遍历行或列都可以 对角线赋值1
        }

        //base矩阵 n次方 我们利用n 的二进制位 如前面举例 n=75 => 1001011 最右侧开始位 与运算 1  判断位是否为1 为1 就表示要进行次方相乘 否则就无需相乘 跳过
        //定义一个辅助数组存放base 用来进行累乘
        int[][] temp = base;
        //遍历次方 每个往右移动一位 也就是次方数n 每次都除以2 递减
        for(; n != 0; n >>= 1){
            if((n & 1) != 0){
                //说明当前位是1, 需要进行temp相乘 刷新res 结果矩阵
                res = getPower(res,temp);
            }
            //接着会右移一位 次方也需要相乘起来  接着要把辅助的矩阵也同步要往高位得到新的值  也就是需要 自身*自身 比如来到 第2位 那么矩阵就是2次方值 3位就是3次方值
            temp = getPower(temp,temp);
        }
        return res;
    }

    //对两个矩阵进行相乘得到新矩阵值
    //
    // a b  *  e f
    // c d     g h
    //[[a,b][c,d]] * [[e,f][g,h]] = [a*e+b*g, a*f+b*h] [c*e+d*g, c*f+d*h]
    public static int[][] getPower(int[][] a, int[][] b){
        int rowa = a.length;        //矩阵a 行
        int colb = b[0].length;     //矩阵b  列
        int cola = a[0].length;     //矩阵a  列  根据矩阵运算的定义 a矩阵列 是跟b矩阵的行一致的 因为每次都是 某一行 a每列 要跟 b某一列 每行对应相乘 相加

        //定义一个结果矩阵 行数对应a矩阵的行   列数对应b矩阵的列
        int[][] res = new int[rowa][colb];
        for(int ra = 0 ; ra < rowa; ra++){
            for(int cb = 0; cb < colb; cb++){
                for(int ca = 0; ca < cola; ca++){
                    //这里ca 列 等同于 b矩阵的 行  ,所以可以共用
                    //矩阵0,0  就等于 a矩阵第0行  b矩阵第0列 每个位置一一相乘 再一一累加 a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0]...
                    //矩阵0,1       a矩阵第0行   b矩阵第1列...
                    //矩阵1,0              1           0...
                    res[ra][cb] += a[ra][ca] * b[ca][cb];
                }
            }
        }
        return res;
    }


    public static void main(String[] args) {
        for (int i = 0; i != 20; i++) {
            System.out.println(getNum1(i));
            System.out.println(getNum2(i));
            System.out.println(getNum3(i));
            System.out.println(t(i));
            System.out.println("===================");
        }

    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值