【python】【矩阵快速幂】【超时解决】3335.字符串转换后的长度I

3335.字符串转换后的长度I
根据题意,可以将本题抽象为:

  1. v [ i ] v[i] v[i] 表示字符表第i个字母(下标从0开始)在s串中的频数
  2. v [ 0.....24 ] v[0.....24] v[0.....24]的元素全部往右移一位, v [ 25 ] v[25] v[25]被加在 v [ 0 ] v[0] v[0] v [ 1 ] v[1] v[1]
  3. 每次变换可以看成是v乘上一个矩阵A

A = [ 0 1 0 0 ⋯ 0 0 0 0 0 1 0 ⋯ 0 0 0 0 0 0 1 ⋯ 0 0 0 ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ ⋮ ⋮ 0 0 0 0 ⋯ 0 1 0 0 0 0 0 ⋯ 0 0 1 1 1 0 0 ⋯ 0 0 0 ] A= \begin{bmatrix} 0&1&0&0&\cdots&0&0&0\\ 0&0&1&0&\cdots&0&0&0\\ 0&0&0&1&\cdots&0&0&0\\ \vdots&\vdots&\vdots&\vdots&\ddots & \vdots&\vdots&\vdots \\ 0&0&0&0&\cdots &0&1&0\\ 0&0&0&0&\cdots &0&0&1\\ 1&1&0&0&\cdots &0&0&0\\ \end{bmatrix} A= 000001100001010000001000000000000100000010
所以整个代码可以分为三部分:

  • 矩阵幂运算函数
  • 向量与矩阵相乘函数
  • 求结果向量的元素和(即主函数)

这是我的最初的代码

MOD = 10** 9 + 7
class Solution:
    def lengthAfterTransformations(self, s: str, t: int) -> int:
        def mat_mul(a: List[List[int]], b: List[List[int]]) -> List[List[int]]:
            m, n, l = len(a), len(a[0]), len(b[0])
            res = [[0 for _ in range(l)] for _ in range(m)]
            for i in range(m):
                for j in range(l):
                    for k in range(n):
                        res[i][j] = (res[i][j] + a[i][k] * b[k][j] % MOD)%MOD
            return res
    
        def mat_pow(a: List[List[int]], p: int) -> List[List[int]]:
            n = len(a)
            res = [[0 for _ in range(n)] for _ in range(n)]
            for i in range(26):
                res[i][i] = 1
            while p:
                if(p&1):
                    res = mat_mul(res, a)
                a = mat_mul(a, a)
                p >>= 1
            return res

        n = len(s)
        # 字母频数用向量v表示
        v = [[0 for _ in range(26)]]
        A = [[0 for _ in range(26)] for _ in range(26)]
        for i in range(1, 26):
            A[i-1][i] = 1
        A[25][0] = A[25][1] = 1
        for i in range(n):
            v[0][ord(s[i])- ord('a')] += 1
        
        A = mat_pow(A, t)
        v = mat_mul(v, A)

        ans = 0
        for i in range(26):
            ans = (ans + v[0][i]) % MOD
        return ans

【超时】,最后一个案例不通过
【python】【矩阵快速幂】【超时解决】3335.字符串转换后的长度I_第1张图片
解决思路:

  • 稀疏性利用:在矩阵乘法中,跳过零元素,减少不必要的乘加操作。
  • 循环顺序调整:将k循环提到j循环外层,提升缓存命中率。
  • 模运算优化:每行计算结束后统一取模,减少运算次数。

主要是对矩阵乘法中的三次循环部分做了优化
原始代码

			for i in range(m):
                for j in range(l):
                    for k in range(n):
                        res[i][j] = (res[i][j] + a[i][k] * b[k][j] % MOD)%MOD

优化后代码

			for i in range(m):
                for k in range(n):
                    a_ik = a[i][k]
                    if a_ik == 0:
                        continue
                    for j in range(l):
                        res[i][j] += a_ik * b[k][j]
                # 统一取模
                for j in range(l):
                    res[i][j] %= MOD

参考:一位大佬言简意赅的题解

你可能感兴趣的:(python,矩阵,leetcode)