矩阵快速幂算法快速上手

矩阵快速幂算法快速上手

    • 一、基础知识回顾
      • [1.1 矩阵乘法](#1.1 矩阵乘法)
      • [1.2 单位矩阵](#1.2 单位矩阵)
    • 二、快速幂算法思想
      • [2.1 整数快速幂](#2.1 整数快速幂)
      • [2.2 矩阵快速幂](#2.2 矩阵快速幂)
    • 三、矩阵快速幂的代码实现
      • [3.1 Python实现](#3.1 Python实现)
      • [3.2 C++实现](#3.2 C++实现)
      • [3.3 Java实现](#3.3 Java实现)
    • 四、矩阵快速幂的应用场景
      • [4.1 斐波那契数列](#4.1 斐波那契数列)
      • [4.2 线性递推数列](#4.2 线性递推数列)
      • [4.3 图论中的路径计数](#4.3 图论中的路径计数)
      • [4.4 动态规划优化](#4.4 动态规划优化)
    • 五、复杂度分析
      • [5.1 时间复杂度](#5.1 时间复杂度)
      • [5.2 空间复杂度](#5.2 空间复杂度)
    • 六、优化方式
      • [6.1 模运算](#6.1 模运算)
      • [6.2 矩阵乘法优化](#6.2 矩阵乘法优化)
      • [6.3 稀疏矩阵优化](#6.3 稀疏矩阵优化)
    • 总结

矩阵快速幂是一个非常实用的算法,它主要用于高效计算矩阵的高次幂,将时间复杂度从朴素的 ( O ( n ) ) (O(n)) (O(n)) 优化到 ( O ( l o g n ) ) (O(log n)) (O(logn)),在处理递推关系、线性变换等问题时具有显著优势。本文我将探讨矩阵快速幂的原理、实现细节及其在不同场景下的应用。

一、基础知识回顾

1.1 矩阵乘法

矩阵乘法是矩阵快速幂的基础运算。对于两个矩阵 ( A ) (A) (A) 和 ( B ) (B) (B),若 (A) 是 ( m × n ) (m × n) (m×n) 的矩阵, ( B ) (B) (B) 是 (n × p) 的矩阵,则它们的乘积 (C = A × B) 是一个 (m × p) 的矩阵,其中 ( C ) (C) (C) 的每个元素 ( C i , j ) (C_{i,j}) (Ci,j) 定义为:

C i , j = ∑ k = 1 n A i , k × B k , j C_{i,j} = \sum_{k=1}^{n} A_{i,k} \times B_{k,j} Ci,j=∑k=1nAi,k×Bk,j

矩阵乘法满足结合律,即 ( ( A × B ) × C = A × ( B × C ) ) ((A \times B) \times C = A \times (B \times C)) ((A×B)×C=A×(B×C)),但不满足交换律,即 ( A × B ) (A \times B) (A×B) 不一定等于 ( B × A ) (B \times A) (B×A)。

1.2 单位矩阵

单位矩阵是一个特殊的方阵,其主对角线上的元素全为1,其余元素全为0,通常用 ( I ) (I) (I) 表示。对于任意矩阵 ( A ) (A) (A),有 ( A × I = I × A = A ) (A \times I = I \times A = A) (A×I=I×A=A)。例如,3阶单位矩阵为:

I = [ 1 0 0 0 1 0 0 0 1 ] I = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} I= 100010001

二、快速幂算法思想

2.1 整数快速幂

快速幂算法的核心思想是分治。以计算整数 (a) 的 (n) 次幂为例,若直接使用循环累乘,时间复杂度为 (O(n))。而快速幂算法通过不断将指数减半,将时间复杂度优化到 (O(log n))。

具体步骤如下:

  1. 若 ( n = 0 ) (n = 0) (n=0),则 ( a n = 1 ) (a^n = 1) (an=1)
  2. 若 n n n 为偶数,则 ( a n = ( a n / 2 ) 2 ) (a^n = (a^{n/2})^2) (an=(an/2)2)
  3. 若 n n n 为奇数,则 ( a n = a × ( a ( n − 1 ) / 2 ) 2 ) (a^n = a \times (a^{(n-1)/2})^2) (an=a×(a(n−1)/2)2)

例如,计算 ( 3 13 ) (3^{13}) (313) 的过程如下:

3 13 = 3 × ( 3 6 ) 2 = 3 × ( ( 3 3 ) 2 ) 2 = 3 × ( ( 3 × ( 3 1 ) 2 ) 2 ) 2 = 3 × ( ( 3 × ( 3 × ( 3 0 ) 2 ) 2 ) 2 ) 2 = 3 × ( ( 3 × ( 3 × 1 2 ) 2 ) 2 ) 2 = 3 × ( ( 3 × 3 2 ) 2 ) 2 = 3 × ( 3 3 ) 2 ) 2 = 3 × 27 2 ) 2 = 3 × 729 2 = 3 × 531441 = 1594323 \begin{align*} 3^{13} &= 3 \times (3^6)^2 \\ &= 3 \times ((3^3)^2)^2 \\ &= 3 \times ((3 \times (3^1)^2)^2)^2 \\ &= 3 \times ((3 \times (3 \times (3^0)^2)^2)^2)^2 \\ &= 3 \times ((3 \times (3 \times 1^2)^2)^2)^2 \\ &= 3 \times ((3 \times 3^2)^2)^2 \\ &= 3 \times (3^3)^2)^2 \\ &= 3 \times 27^2)^2 \\ &= 3 \times 729^2 \\ &= 3 \times 531441 \\ &= 1594323 \end{align*} 313=3×(36)2=3×((33)2)2=3×((3×(31)2)2)2=3×((3×(3×(30)2)2)2)2=3×((3×(3×12)2)2)2=3×((3×32)2)2=3×(33)2)2=3×272)2=3×7292=3×531441=1594323

2.2 矩阵快速幂

将快速幂的思想应用到矩阵上,就得到了矩阵快速幂算法。对于矩阵 ( A ) (A) (A) 和正整数 ( n ) (n) (n),计算 ( A n ) (A^n) (An) 的步骤与整数快速幂类似:

  1. 若 ( n = 0 ) (n = 0) (n=0),则 ( A n = I ) (A^n = I) (An=I)(单位矩阵)
  2. 若 n n n 为偶数,则 ( A n = ( A n / 2 ) 2 ) (A^n = (A^{n/2})^2) (An=(An/2)2)
  3. 若 n n n 为奇数,则 ( A n = A × ( A ( n − 1 ) / 2 ) 2 ) (A^n = A \times (A^{(n-1)/2})^2) (An=A×(A(n−1)/2)2)

由于矩阵乘法满足结合律,上述步骤是可行的。

三、矩阵快速幂的代码实现

3.1 Python实现

python 复制代码
def matrix_multiply(a, b):
    """矩阵乘法"""
    rows_a = len(a)
    cols_a = len(a[0])
    rows_b = len(b)
    cols_b = len(b[0])
    
    if cols_a != rows_b:
        raise ValueError("矩阵A的列数必须等于矩阵B的行数")
    
    result = [[0 for _ in range(cols_b)] for _ in range(rows_a)]
    
    for i in range(rows_a):
        for j in range(cols_b):
            for k in range(cols_a):
                result[i][j] += a[i][k] * b[k][j]
    
    return result

def matrix_power(matrix, n):
    """矩阵快速幂"""
    rows = len(matrix)
    cols = len(matrix[0])
    
    if rows != cols:
        raise ValueError("矩阵必须是方阵才能计算幂")
    
    # 初始化结果为单位矩阵
    result = [[1 if i == j else 0 for j in range(rows)] for i in range(rows)]
    
    while n > 0:
        if n % 2 == 1:
            result = matrix_multiply(result, matrix)
        matrix = matrix_multiply(matrix, matrix)
        n //= 2
    
    return result

# 示例:计算斐波那契数列第n项
def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    
    # 斐波那契数列的矩阵表示
    matrix = [[1, 1], [1, 0]]
    result = matrix_power(matrix, n - 1)
    return result[0][0]

# 测试
print(fibonacci(10))  # 输出55

3.2 C++实现

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

// 矩阵乘法
vector<vector<long long>> matrixMultiply(const vector<vector<long long>>& a, const vector<vector<long long>>& b) {
    int rows_a = a.size();
    int cols_a = a[0].size();
    int rows_b = b.size();
    int cols_b = b[0].size();
    
    if (cols_a != rows_b) {
        throw invalid_argument("矩阵A的列数必须等于矩阵B的行数");
    }
    
    vector<vector<long long>> result(rows_a, vector<long long>(cols_b, 0));
    
    for (int i = 0; i < rows_a; ++i) {
        for (int j = 0; j < cols_b; ++j) {
            for (int k = 0; k < cols_a; ++k) {
                result[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    
    return result;
}

// 矩阵快速幂
vector<vector<long long>> matrixPower(vector<vector<long long>> matrix, long long n) {
    int rows = matrix.size();
    int cols = matrix[0].size();
    
    if (rows != cols) {
        throw invalid_argument("矩阵必须是方阵才能计算幂");
    }
    
    // 初始化结果为单位矩阵
    vector<vector<long long>> result(rows, vector<long long>(cols, 0));
    for (int i = 0; i < rows; ++i) {
        result[i][i] = 1;
    }
    
    while (n > 0) {
        if (n % 2 == 1) {
            result = matrixMultiply(result, matrix);
        }
        matrix = matrixMultiply(matrix, matrix);
        n /= 2;
    }
    
    return result;
}

// 计算斐波那契数列第n项
long long fibonacci(long long n) {
    if (n == 0) {
        return 0;
    } else if (n == 1) {
        return 1;
    }
    
    // 斐波那契数列的矩阵表示
    vector<vector<long long>> matrix = {{1, 1}, {1, 0}};
    vector<vector<long long>> result = matrixPower(matrix, n - 1);
    return result[0][0];
}

int main() {
    cout << fibonacci(10) << endl;  // 输出55
    return 0;
}

3.3 Java实现

java 复制代码
import java.util.Arrays;

public class MatrixExponentiation {
    
    // 矩阵乘法
    public static long[][] matrixMultiply(long[][] a, long[][] b) {
        int rowsA = a.length;
        int colsA = a[0].length;
        int rowsB = b.length;
        int colsB = b[0].length;
        
        if (colsA != rowsB) {
            throw new IllegalArgumentException("矩阵A的列数必须等于矩阵B的行数");
        }
        
        long[][] result = new long[rowsA][colsB];
        
        for (int i = 0; i < rowsA; i++) {
            for (int j = 0; j < colsB; j++) {
                for (int k = 0; k < colsA; k++) {
                    result[i][j] += a[i][k] * b[k][j];
                }
            }
        }
        
        return result;
    }
    
    // 矩阵快速幂
    public static long[][] matrixPower(long[][] matrix, long n) {
        int rows = matrix.length;
        int cols = matrix[0].length;
        
        if (rows != cols) {
            throw new IllegalArgumentException("矩阵必须是方阵才能计算幂");
        }
        
        // 初始化结果为单位矩阵
        long[][] result = new long[rows][cols];
        for (int i = 0; i < rows; i++) {
            result[i][i] = 1;
        }
        
        while (n > 0) {
            if (n % 2 == 1) {
                result = matrixMultiply(result, matrix);
            }
            matrix = matrixMultiply(matrix, matrix);
            n /= 2;
        }
        
        return result;
    }
    
    // 计算斐波那契数列第n项
    public static long fibonacci(long n) {
        if (n == 0) {
            return 0;
        } else if (n == 1) {
            return 1;
        }
        
        // 斐波那契数列的矩阵表示
        long[][] matrix = {{1, 1}, {1, 0}};
        long[][] result = matrixPower(matrix, n - 1);
        return result[0][0];
    }
    
    public static void main(String[] args) {
        System.out.println(fibonacci(10));  // 输出55
    }
}

四、矩阵快速幂的应用场景

4.1 斐波那契数列

斐波那契数列是矩阵快速幂最经典的应用场景。斐波那契数列的递推公式为:

F ( n ) = F ( n − 1 ) + F ( n − 2 ) ( n ≥ 2 ) , F ( 0 ) = 0 , F ( 1 ) = 1 \] \[ F(n) = F(n-1) + F(n-2) \\quad (n \\geq 2), \\quad F(0) = 0, F(1) = 1 \] \[F(n)=F(n−1)+F(n−2)(n≥2),F(0)=0,F(1)=1

可以用矩阵表示为:

F ( n ) F ( n − 1 ) \] = \[ 1 1 1 0 \] × \[ F ( n − 1 ) F ( n − 2 ) \] \\begin{bmatrix}F(n) \\\\F(n-1)\\end{bmatrix}=\\begin{bmatrix} 1 \& 1 \\\\ 1 \& 0 \\end{bmatrix} \\times \\begin{bmatrix} F(n-1) \\\\ F(n-2) \\end{bmatrix} \[F(n)F(n−1)\]=\[1110\]×\[F(n−1)F(n−2)

进一步递推得到:

F ( n ) F ( n − 1 ) \] = \[ 1 1 1 0 \] n − 1 × \[ F ( 1 ) F ( 0 ) \] \\begin{bmatrix}F(n) \\\\F(n-1)\\end{bmatrix}=\\begin{bmatrix} 1 \& 1 \\\\ 1 \& 0 \\end{bmatrix}\^{n-1} \\times \\begin{bmatrix} F(1) \\\\ F(0) \\end{bmatrix} \[F(n)F(n−1)\]=\[1110\]n−1×\[F(1)F(0)

因此,计算 ( F ( n ) ) (F(n)) (F(n)) 等价于计算矩阵的 ( n − 1 ) (n-1) (n−1) 次幂,时间复杂度为 ( O ( l o g n ) ) (O(log n)) (O(logn))。

4.2 线性递推数列

矩阵快速幂可以推广到求解任何线性递推数列,例如:

a ( n ) = c 1 a ( n − 1 ) + c 2 a ( n − 2 ) + ⋯ + c k a ( n − k ) \] \[ a(n) = c_1a(n-1) + c_2a(n-2) + \\cdots + c_ka(n-k) \] \[a(n)=c1a(n−1)+c2a(n−2)+⋯+cka(n−k)

可以构造 ( k × k ) (k \times k) (k×k) 的转移矩阵,将问题转化为矩阵快速幂问题,时间复杂度同样为 ( O ( log ⁡ n ) ) (O(\log n)) (O(logn))。

4.3 图论中的路径计数

在图论中,邻接矩阵 (A) 的 (n) 次幂 ( A n ) (A^n) (An) 中的元素 ( A i , j n ) (A^n_{i,j}) (Ai,jn) 表示从节点 ( i ) (i) (i) 到节点 ( j ) (j) (j) 的长度为 (n) 的路径数目。利用矩阵快速幂可以高效计算这种路径数目。

4.4 动态规划优化

在某些动态规划问题中,状态转移方程具有线性性质,可以使用矩阵快速幂优化时间复杂度。例如,在一些涉及大量状态转移的问题中,将转移过程表示为矩阵乘法,然后使用快速幂加速计算。

五、复杂度分析

5.1 时间复杂度

矩阵快速幂的时间复杂度主要由两部分组成:

  1. 矩阵乘法的时间复杂度:朴素的矩阵乘法算法时间复杂度为 ( O ( k 3 ) ) (O(k^3)) (O(k3)),其中 ( k ) (k) (k) 是矩阵的阶数。
  2. 快速幂的迭代次数:由于每次迭代将指数减半,迭代次数为 ( O ( l o g n ) ) (O(log n)) (O(logn))。

因此,矩阵快速幂的总时间复杂度为 ( O ( k 3 l o g n ) ) (O(k^3 log n)) (O(k3logn))。

5.2 空间复杂度

矩阵快速幂的空间复杂度主要取决于存储矩阵所需的空间,为 ( O ( k 2 ) ) (O(k^2)) (O(k2)),其中 ( k ) (k) (k) 是矩阵的阶数。

六、优化方式

6.1 模运算

在实际应用中,矩阵元素可能会非常大,需要进行模运算以避免溢出。在矩阵乘法和快速幂的过程中,每一步都可以对结果取模。

6.2 矩阵乘法优化

对于大规模矩阵,可以使用Strassen算法等优化矩阵乘法的时间复杂度至 ( O ( k 2.807 ) ) (O(k^{2.807})) (O(k2.807)),但在实际应用中,当 ( k ) (k) (k) 较小时,朴素算法可能更高效。

6.3 稀疏矩阵优化

如果矩阵是稀疏的,可以利用稀疏矩阵的特性优化乘法运算,减少不必要的计算。

总结

矩阵快速幂是一种高效的算法,能够将矩阵高次幂的计算时间从 ( O ( n ) ) (O(n)) (O(n)) 优化到 ( O ( l o g n ) ) (O(log n)) (O(logn)),在处理线性递推关系、图论路径计数等问题时具有显著优势。通过本文讲解,想必你已经初步掌握了矩阵快速幂的基本原理、实现方法及应用场景,以后在实际使用中需要根据具体问题选择合适的矩阵表示和优化策略,以达到最佳的算法效率。

That's all, thanks for reading!

觉得有用就点个赞、收进收藏夹吧!关注我,获取更多干货~

相关推荐
Steve lu15 分钟前
回归任务损失函数对比曲线
人工智能·pytorch·深度学习·神经网络·算法·回归·原力计划
蒙奇D索大1 小时前
【数据结构】图论核心算法解析:深度优先搜索(DFS)的纵深遍历与生成树实战指南
数据结构·算法·深度优先·图论·图搜索算法
让我们一起加油好吗1 小时前
【基础算法】高精度(加、减、乘、除)
c++·算法·高精度·洛谷
不会敲代码的灵长类1 小时前
机器学习算法-k-means
算法·机器学习·kmeans
Studying 开龙wu1 小时前
机器学习有监督学习sklearn实战二:六种算法对鸢尾花(Iris)数据集进行分类和特征可视化
学习·算法·机器学习
鑫鑫向栄1 小时前
[蓝桥杯]缩位求和
数据结构·c++·算法·职场和发展·蓝桥杯
Tony__Ferguson1 小时前
简述八大排序(Sort)
数据结构·算法·排序算法
芜湖xin1 小时前
【题解-洛谷】P9422 [蓝桥杯 2023 国 B] 合并数列
算法·队列
鑫鑫向栄2 小时前
[蓝桥杯]外卖店优先级
数据结构·c++·算法·职场和发展·蓝桥杯
<但凡.2 小时前
题海拾贝:P8598 [蓝桥杯 2013 省 AB] 错误票据
数据结构·算法·蓝桥杯