【矩阵快速幂】太震惊了!直接把斐波那契从6s优化到了0毫秒....

news2024/11/17 7:40:27

今天我们来学习一个新的专题,「快速幂」技巧。

斐波那契数列 相信大家都不陌生,小学的找规律题目中就经常见到它的身影。

递推表达式为:

根据该表达式,可以很轻松的写出递归版本的代码:

public static int f(int n) {
    if (n < 1) {
        return 0;
    }
    if (n == 1 || n == 2) {
        return 1;
    }
    return f(n - 1) + f(n - 2);
}

该递归代码非常容易理解,这里不做过多讲解。相信小伙伴们也都知道其存在的问题:包含了大量的重复计算!


接下来就引出我们今天要介绍的 「矩阵快速幂」 技巧。

注意:以下内容需要用到 线性代数 中的 矩阵乘积 运算哦~

关系推导

我们将 两个相邻项 写成矩阵形式,由此可以得到如下关系式:

将右侧通过 矩阵乘积 提出 系数矩阵 后得到:

(这是不是就变成了数列的递推式了)

我们惊讶的发现,最终要求的 F n Fn Fn 只和系数矩阵的 n − 2 n-2 n2 次幂以及数列的前两项的值(已知)有关。

推导到这里,我们关注的焦点就聚焦在了如何快速求出某个 矩阵的高次幂

在介绍 矩阵高次幂 前,我们先来回顾一下 幂运算

数的高次幂

在这里插入图片描述

这个公式对于计算高次幂来说有何启发呢?

计算机对于二进制的计算非常方便快捷,因此我们就想到,如果我们将高次幂的计算划归成与二进制有关的计算是不是就方便很多了呢~

下面我们通过一个例子进行说明:

分解后,对于每一项的计算都变得很简单了,只需要底数 13 依次与自己相乘,就能按照 1、2、4、8、16…的指数增长了。计算答案只需将指数 27 的二进制中含有 1 的项乘入结果中,最终就能完成计算。时间复杂度仅为 O ( l o g N ) O(logN) O(logN)(如果直接底数一遍一遍的相乘复杂度为 O ( N ) O(N) O(N))。

public static long fastPower(long base, long p) {
    long res = 1;
    // 指数不为 0 就一直循环,指数右移一位
    for (; p != 0; p >>= 1) {
        // 只有当前末位为 1 时,结果res中乘入此时的底数base
        if ((p & 1) != 0) {
            res *= base;
        }
        // 底数依次与自己相乘,得到 1、2、4、8、16 次方
        base *= base;
    }
    return res;
}

矩阵高次幂

在了解了数字高次幂的计算方法后,矩阵的高次幂怎么计算,想必小伙伴们也都有思路了。对应过来就行啦~

注意: 数字里的 1 ,在矩阵中为 单位矩阵E

直接看代码:

private static int[][] matrixPower(int[][] m, int p) {
    int[][] res = new int[m.length][m[0].length];
    // 构造单位矩阵 E
    for (int i = 0; i < res.length; i++) {
        res[i][i] = 1;
    }
    int[][] t = m;
    // 与计算数的高次幂方法一致
    for (; p != 0; p >>= 1) {
        if ((p & 1) != 0) {
            res = produce(res, t);
        }
        t = produce(t, t);
    }
    // 返回计算出的高次幂矩阵
    return res;
}

// 计算两个矩阵相乘的结果矩阵
private static int[][] produce(int[][] a, int[][] b) {
    int n = a.length;
    int m = b[0].length;
    int k = a[0].length;
    int[][] ans = new int[n][m];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            for (int c = 0; c < k; c++) {
                ans[i][j] += a[i][c] * b[c][j];
            }
        }
    }
    return ans;
}

到这里,我们就解决了矩阵的高次幂问题。


回归主线,对于解决斐波那契数列的第 N 项来说,在得到系数矩阵的 n − 2 n-2 n2 次方后即可计算出来。

快速幂求解斐波那契代码

public static int f(int n) {
    if (n < 1) {
        return 0;
    }
    if (n == 1 || n == 2) {
        return 1;
    }
    int[][] base = { { 1, 1 }, { 1, 0 } };
    // 计算系数矩阵的高次幂
    int[][] res = matrixPower(base, n - 2);
    // res中 00 和 01 位置求和,即 a+b
    return res[0][0] + res[0][1];
}

当求解一个较大的斐波那契数 F ( 46 ) F(46) F(46) 时,两种不同算法的执行时间对比也很明显:


本题结合了线性代数的知识,可能稍微有点儿难度,小伙伴们认真体会思想哦~

学完整个思路我们发现:其实最关键的是 系数矩阵的求解 。本题的系数矩阵是通过递推公式得到的。

换一道题目,不同的递推公式就会对应不同的系数矩阵哦!接下来的几篇文章我们继续加深对于 系数矩阵的求解方法

~ 点赞 ~ 关注 ~ 星标 ~ 不迷路 ~!!!

关注回复「ACM紫书」获取 ACM 算法书籍~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1615221.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言进阶】指针例题大杂烩,阁下是高手还是菜鸟?

前言 首先说明&#xff0c;本文不适合新手&#xff0c;如果你刚刚接触指针&#xff0c;可以看看前五点&#xff0c;这是我认为指针中比较重要的细节&#xff0c;例题部分酌情尝试。 如果你自认为指针学的不错&#xff0c;胸有成竹&#xff0c;请尝试最后的例题&#xff0c;如…

如何用网页绘制一个黑莓9900的键盘效果图

如何用网页绘制一个黑莓9900的键盘效果图 入了几个黑莓蓝牙键盘&#xff0c;出于喜好&#xff0c;想做一个跟实体键盘一模一样的网页界面。 最终的实现效果是这样的&#xff1a; 在线查看&#xff1a;http://kylebing.cn/tools/bb-keyboard 点击上面四个按键显示不同模型界面…

【C++】适配器· 优先级队列 仿函数 反向迭代器

目录 适配器&#xff1a;适配器的应用&#xff1a;1. 优先级队列&#xff1a;仿函数&#xff1a;更深入的了解仿函数&#xff1a;一个关于不容易被注意的知识点&#xff1a; 2. 反向迭代器&#xff1a;&#xff08;list为例&#xff09; 适配器&#xff1a; 我们先来谈来一下容…

CentOS 7安装、卸载MySQL数据库(一)

说明&#xff1a;本文介绍如何在CentOS 7操作系统下使用yum方式安装MySQL数据库&#xff0c;及卸载&#xff1b; 安装 Step1&#xff1a;卸载mariadb 敲下面的命令&#xff0c;查看系统mariadb软件包 rpm -qa|grep mariadb跳出mariadb软件包信息后&#xff0c;敲下面的命令…

OpenStack云计算(十)——OpenStack虚拟机实例管理,增加一个计算节点并进行实例冷迁移,增加一个计算节点的步骤,实例冷迁移的操作方法

项目实训一 本实训任务对实验环境要求较高&#xff0c;而且过程比较复杂&#xff0c;涉及的步骤非常多&#xff0c;有一定难度&#xff0c;可根据需要选做。可以考虑改为直接观看相关的微课视频 【实训题目】 增加一个计算节点并进行实例冷迁移 【实训目的】 熟悉增加一个…

力扣110. 平衡二叉树

思路&#xff1a;与二叉树最大高度类似&#xff0c;但是这里需要返回 -1 的高度来标识不是平衡二叉树&#xff0c;判断左右子树的高度相差大于1则不平衡&#xff0c;否则就是平衡。 class Solution {public boolean isBalanced(TreeNode root) {int ans func(root);if(ans >…

向Linux内核添加新功能的静态加载与动态加载

目录 向Linux内核添加新功能的静态加载与动态加载 开发环境&#xff1a; 一、静态加载法 1、新功能源码与Linux内核源码在同一个目录结构下 2、给新功能代码配置Kconfig 3、给新功能代码改写Makefile 4、使用make menuconfig 在配置界面里将新功能对应的那项选择成<*&…

AI商业智能的一些分享

本文主要讲AI商业相关的&#xff08;特别是营销相关的&#xff09;一些知识点&#xff0c;比较零散。 简单总结 AI商业智能&#xff1a; 1&#xff09;将人员经验抽象化为算法规则&#xff0c; 2)打造数据驱动的精益运营能力&#xff0c; 3)长期保持价格竞争力并将商品毛利让…

Java中的重写

package day34; ​ public class Father {String name;int age;public void 输出(){System.out.println("father");} } ​ package day34; ​ public class Son extends Father{Overridepublic void 输出() {System.out.println("son");} } ​ package d…

【LAMMPS学习】八、基础知识(3.8)计算扩散系数

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

Spring基础 SpringAOP

前言 我们都知道Spring中最经典的两个功能就是IOC和AOP 我们之前也谈过SpringIOC的思想 容器编程思想了 今天我们来谈谈SpringAOP的思想 首先AOP被称之为面向切面编程 实际上面向切面编程是面向对象的编程的补充和完善 重点就是对某一类问题的集中处理 前面我们写的统一异常管理…

2024接口自动化测试入门基础知识【建议收藏】

接口自动化测试是指通过编写测试脚本和使用相关工具&#xff0c;对软件系统的接口进行自动化测试的过程。 今天本文从4个方面来介绍接口自动化测试入门基础知识 一、接口自动化测试是什么&#xff1f; 二、接口自动化测试流程&#xff1f; 三、接口自动化测试核心知识点有那些…

Linux--uboot移植(二)

修改uboot以匹配开发板的方式有两种&#xff0c;一种是在NXP原厂开发板i.MX 6ULL EVK的文件上进行修改&#xff0c;另一种仿造NXP的开发板文件&#xff0c;添加自己的开发板文件。 为了能更多的了解uboot&#xff0c;我们使用代码改动较大的第二种方式进行uboot的移植。 在修…

HTML5+JavaScript实现语音合成(文字转语音)

HTML5JavaScript实现语音合成&#xff08;文字转语音&#xff09; 本文介绍用HTML5和JavaScript实现语音合成朗读&#xff08;文字转语音&#xff09;。 Web Speech API 有两个部分&#xff1a;SpeechSynthesis 语音合成&#xff08;文本到语音 TTS&#xff09;和 SpeechReco…

双周回顾#009 - 大黄和我

双周回顾#009 - 大黄和我 说一个笑话&#xff0c;被朋友催更了&#xff0c;这就有点尴尬了&#xff01;&#xff01;&#xff01; 最近一个月&#xff0c;把空闲时间都点在了“玩”上&#xff0c;看闲书、玩游戏、背包客。 部落冲突 《埃隆马斯克传》一书中&#xff0c;马斯…

ubunt18.04安装ROS避坑指南

1 前言&#xff1a; 本文是ubunt18.04下安装ros的&#xff0c;如果想使用ros2,请看我的下一篇文章,ubunt18.04安装ROS2 本来是不该写的&#xff0c;有官方文档&#xff0c;还有很多大神的分析。但里面的坑太多&#xff0c;我考虑了一下&#xff0c;还是想记录下避免下次在跳泥…

day06 51单片机-点阵led

1 点阵LED 1.1 需求描述 本案例介绍如何使用点阵LED显示一排由左上到右下的斜线。 1.2 硬件设计 1.2.1 硬件原理图 点阵内部的原理图: 点阵LED的原理也非常简单,就是LED点灯。例如,我们想要让13列(阳极端)9行(阴极端)的LED点亮,需要13为高电平,9为低电平。注意对于…

《王者荣耀》游戏攻略:角色排行榜——墨子

作为天蝎座黄金圣斗士&#xff0c;墨子以他的正义感和荣誉感闻名&#xff0c;一直站在正义的一方&#xff0c;忠于女神雅典娜。他的猩红毒针象征着审判和死亡&#xff0c;而他所施加的十五针“安达里士”更是生命终结的预兆。在冥王再次发动战争之际&#xff0c;墨子追随雅典娜…

ResNet详解

一、认识ResNet ResNet&#xff08;Residual Network&#xff09;是一种深度神经网络结构&#xff0c;被广泛应用于图像分类、目标检测和语义分割等计算机视觉任务中。它是由微软亚洲研究院的何凯明等人于2015年提出的&#xff0c;通过引入残差连接&#xff08;residual conne…

javaScript3

javaScript 一.对象1.概念2.创建对象的三种方法(1).字面量创建&#xff08;利用{}&#xff09;(2)变量、属性、函数、方法的区别(3).new Object创建(4).构造函数 3.new关键字的执行过程4.遍历对象&#xff08;for..in) 二.内置对象 一.对象 1.概念 一组无序的相关属性和方法的…