代码调优?从Fibonacci数列的7种写法说起,看完coding能力上一个台阶

news2025/1/15 6:53:01

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

引子

楼梯有 N阶,上楼可以一步上一阶,也可以一步上二阶。

编一个程序,计算共有多少种不同的走法。

例:

  • 0层:1种
  • 1层:1种
  • 2层:2种
  • 3层:3种
  • 4层:5种
  • ...

洛谷题链(原题需要压位高精、矩阵快速幂,本文只讨论该问题的常规解法及优化思路)

解题思路

走楼梯,要么一次走一阶,要么一次走两阶,那我每次的走法就等于=上一阶的方案数+上上阶的方案种数,这就推出了方程:

f[i]=f[i-1]+f[i-2]

同时考虑边界:0阶或者1阶的答案都是1种。

由此将问题转化为求解Fibonacci数列(也叫兔子数列,黄金分割数列,斐波那契数列等)第n阶。

基操写法(递推)

我们已知第n阶等于第n-1阶加第n-2阶,直接使用循环递推即可

const getFibonacci = (n) => {
    let fibonacciArr = [1,1];
    if (n < 2) return a[n];
    for (let i = 2; i <= n; i++) {
        if (i < n) fibonacciArr.push(fibonacciArr[i - 1] + fibonacciArr[i - 2]);
        else return fibonacciArr[i - 1] + fibonacciArr[i - 2];
    }
};
复制代码

递推 + 滚动压缩

已知方程f[i]=f[i-1]+f[i-2]只使用了i,i-1,i-2

所以可以滚动压缩,节省数组开销,得到 f[i%3]=f[(i+1)%3]+f[(i+2)%3]

const getFibonacci = (n) => {
    let fibonacciArr = [1, 1, 2];
    if (n < 3) return fibonacciArr[n];
    for (let i = 3; i <= n; i++) {
        fibonacciArr[i % 3] = fibonacciArr[(i - 1) % 3] + fibonacciArr[(i - 2) % 3];
        if (i == n) return fibonacciArr[i % 3];
    }
};
复制代码

基操写法(递规)

根据公式f[i]=f[i-1]+f[i-2],同时递归边界n==0||n==1,可以很容易地写出递归写法

const getFibonacci = (n) => {
    if(n==0||n==1)return 1;
    return getFibonacci(n - 1) + getFibonacci(n - 2);
};
复制代码

很明显,当n逐渐增大时,运算速度指数级递增(一般计算机在求解n=40时开始吃力),原因留在评论区由大家探讨

递归 + 记忆化搜索

递归写法最常见的问题就是重复搜索,所以可以使用记忆化搜索(将查到的结果存起来)进一步优化

let fibonacciData = { 0: 1, 1: 1 };
const getFibonacci = (n) => {
    if (fibonacciData[n]) return fibonacciData[n];
    return (fibonacciData[n] = getFibonacci(n - 1) + getFibonacci(n - 2));
};
复制代码

递归 + 滚动压缩

同理,可以通过滚动压缩对递归进行优化

const getFibonacci = (first, second, current, n) => {
    if(n<2)return 1;
    if (current == n) return first + second;
    return getFibonacci(first + second, first, current + 1, n);
};
复制代码

柯里化

可以使用柯里化的缓存特性将计算结果储存起来

// 缓存函数
const cached = (fn) => {
    const fibonacciData = {};
    return (n) => {
        if (!fibonacciData[n]) {
                fibonacciData[n] = fn(n);
        }
        return fibonacciData[n];
    };
};

const getFibonacci = (n) => {
    if (n < 2) return 1;
    return cachedGetFibonacci(n - 1) + cachedGetFibonacci(n - 2);
};
var cachedGetFibonacci = cached(getFibonacci);

console.log(cachedGetFibonacci(1000));
复制代码

取巧写法(通项公式)

可以使用通项公式(也叫比内公式):

const getFibonacci = (n) => {
    n+=1;
    return ((1 / Math.sqrt(5)) * (Math.pow((1 + Math.sqrt(5)) / 2, n) - Math.pow((1 - Math.sqrt(5)) / 2, n))).toFixed(0);
};
复制代码

这种写法实际上不具有代码研究价值,但是公式的推导实际上具有很高的研究意义(比较难所以不在文中列举了),因为是最高效的写法,所以放到最后来说

总结

可以看出,调优的主要方向有两个大类:节省空间,节省时间;

实际开发过程需要我们去综合空间和时间的实际情况去取舍和调优。

本文是高阶函数/函数抽象的一个引子,本人将在后续进行javaScript进阶相关知识的持续更新。

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

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

相关文章

【毕业设计】28-基于单片机的音乐播放器简易音乐播放器设计(原理图+源代码+仿真工程+答辩PPT+答辩论文)

typora-root-url: ./ 【毕业设计】28-基于单片机的音乐播放器简易音乐播放器设计&#xff08;原理图源代码仿真工程答辩PPT答辩论文&#xff09; 文章目录typora-root-url: ./【毕业设计】28-基于单片机的音乐播放器简易音乐播放器设计&#xff08;原理图源代码仿真工程答辩PP…

麦芽糖-聚乙二醇-甲氨蝶呤 MTX-PEG-maltose

麦芽糖-聚乙二醇-甲氨蝶呤 MTX-PEG-maltose 中文名称&#xff1a;麦芽糖-甲氨蝶呤 英文名称&#xff1a;maltose-MTX 别称&#xff1a;甲氨蝶呤修饰麦芽糖&#xff0c;甲氨蝶呤-麦芽糖 PEG接枝修饰麦芽糖&#xff0c;麦芽糖-聚乙二醇-甲氨蝶呤&#xff0c;MTX-PEG-maltose&…

【visual studio】visual studio 2022 无法 复制黏贴

visual studio 2022 cannot copy paste 其他网友也有反馈到微软&#xff1a;VS 2022 Copy and Paste form feature Broken?Copy paste still not fixed in Visual studio 2022表现是突然就无法复制和黏贴了其他的app 就没有这个问题每次都是重启电脑解决。 2022年11月fix 今…

java中csv导出-追加-列转行

1、问题描述 业务数据量比较大&#xff0c;业务上查询条件写入数据库&#xff0c;java定时去读&#xff0c;然后导出csv&#xff0c;供用户下载&#xff0c;因为有模板要求&#xff0c;前一部分是统计信息&#xff0c;后一部分是明细信息&#xff1b;首先csv中写入统计信息&am…

gradle安装配置

Gradle和Maven都是当前热门的自动化构建工具。 这里以安装6.8版本为例 下载地址 https://services.gradle.org/distributions/ 环境配置 新建系统环境 GRADLE_HOME D:\software\gradle-6.8 新建系统环境 GRADLE_USER_HOME D:\gradle\repository 找到path变量,后面添加 %…

uniapp 短信监听(验证码)插件 Ba-Sms

简介&#xff08;下载地址&#xff09; Ba-Sms 是一款用于拦截实时短信的插件&#xff0c;可以进行短信过滤&#xff0c;得到自己想要的内容&#xff0c;可以用于需要自动填写短信验证码的项目 支持监听当前接收到的短信信息支持过滤接收到的短信&#xff0c;默认过滤4~8位的…

Python学习笔记之进程池pool

平时很多操作都会用到多进程&#xff0c;比如爬虫、数据处理。 下面介绍一下多进程的函数方法、参数及使用方法。 目录 一.进程池Pool介绍 1.apply() 2.apply_async 3.map() 4.map_async() 5.close() 6.terminal() 7.join() 二&#xff0e;进程池Pool使用 1.map用法…

【虚幻引擎UE】UE5 材质动态修改的2种方法(含工程源码)

演示效果&#xff1a; 示例工程源码 一、直接材质参数变量 1、贴图变量&#xff1a; 在材质蓝图中右键&#xff0c;创建变量TextureSampeParameter2D&#xff08;贴图变量&#xff09;。 输入RGB到基础颜色 2、单色变量&#xff1a; 在材质蓝图中右键&#xff0c;创建变量…

[附源码]计算机毕业设计springboot高校商铺管理系统论文

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

要想后期修改少,代码重构要趁早

摘要&#xff1a;在敏捷中&#xff0c;让设计简单化&#xff0c;必须让设计从简单开始&#xff0c;然后变得成熟。要做到这一点&#xff0c;重构是唯一的出路。本文分享自华为云社区《敏捷技术实践之重构》&#xff0c;作者&#xff1a;华为云PaaS服务小智 。 前言 极限编程&…

Flink Forward Asia 2022 主论坛概览

2022 年 11 月 26-27 日&#xff0c;Flink Forward Asia&#xff08;FFA&#xff09;峰会成功举行。Flink Forward Asia 是由 Apache 软件基金会官方授权、由阿里云承办的技术峰会&#xff0c;是目前国内最大的 Apache 顶级项目会议之一&#xff0c;也是 Flink 开发者和使用者的…

使用nohup命令 或者 代码创建守护进程

目录 一、什么是守护进程&#xff1f; 1、守护进程的概念 2、为什么需要守护进程 二、理解进程组、会话、终端 三、创建守护进程的两种方式 1、nohup命令创建守护进程 2、代码创建守护进程 (1) 创建子进程&#xff0c;父进程退出 (2) 子进程创建新的会话 (3) 更改守护…

jsp美食共享平台系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 美食共享平台系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统采用mvc开发结构 serlvetdaobean模式&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用 B/S模式开发。开发环境为TOMCAT7.0,Myecl…

二叉树链式结构-c语言实现

文章目录二叉树链式结构实现1. 链式二叉树结构2. 二叉树的遍历2.1 前序遍历2.2 中序遍历2.3 后序遍历2.4 层序遍历3. 常见功能3.1 二叉树结点个数3.2 二叉树叶子结点个数3.3 第K层结点的个数3.4 二叉树的深度3.5 判断是不是树是不是完全二叉树3.6 在二叉树中查找值为x的结点3.7…

VM系列振弦采集读数模块的测量模式

VM系列振弦采集读数模块的测量模式 模块有连续测量和单次测量两种测量模式&#xff0c; 通过向测量模式寄存器 WKMOD.[0]写入 1 使模块工作于连续测量工作模式&#xff0c; 写入 0 使模块工作于单次测量工作模式。 WKMOD.[15]用来设置是否在模块“ 忙” 时禁用数字接口&#xf…

京东低代码平台:水滴表单联动可视化配置的实现与思考

TL;DR drip-form在0.9.0的alpha版支持了可视化配置联动的功能&#xff08;仍在测试中&#xff09;drip-form通过协议到代码的转换&#xff0c;尽可能降低常见联动配置的开发成本探讨&#xff1a;JSON diff动态生成常见联动和校验drip form的后续更新&#xff1a;v0.9.0是v0最后…

计算机组成原理-总线详细讲解(持续更新中)

总线概念与分类 定义 总线是一组能为多个部件分时共享的公共信息传送线路 共享是指总线上可以挂接多个部件&#xff0c;各个部件之间互相交换的信息都可以通过这组线路分时共享。 分时是指同一时刻只允许有一个部件向总线发送信息&#xff0c;如果系统中有多个部件&#xf…

React源码分析1-jsx转换及React.createElement

jsx 的转换 我们从 react 应用的入口开始对源码进行分析&#xff0c;创建一个简单的 hello, world 应用&#xff1a; import React, { Component } from react; import ReactDOM from react-dom; export default class App extends Component {render() {return <div>h…

科普下抖音的规则,为什么别人的内容很容易火,而我的很难?

今天给大家科普下抖音的规则&#xff0c;为什么别人的内容很容易火&#xff0c;而我的很难&#xff1f; 上一篇给大家讲了现在做抖音还来得及么&#xff1f;肯定的回答&#xff0c;一直都来得及。 既然来得及&#xff0c;那么我们怎么才能做好抖音呢&#xff1f; 在我看来&a…

Rust 基础(四)

十、泛型、Traits和生命周期 每种编程语言都有有效处理概念重复的工具。在Rust中&#xff0c;一个这样的工具就是泛型:具体类型或其他属性的抽象替身。我们可以表达泛型的行为&#xff0c;或者它们如何与其他泛型相关联&#xff0c;而不知道在编译和运行代码时它们的位置会是什…