阿尔戈角n斐波那契

Welcome Back to Algo Corner! This is my little corner of the internet to teach you and me about different algorithm concepts and break down how algorithms work in a fundamental manner. This will all be in Javascript with ES6 formatting.

欢迎回到Algo Corner! 这是我在互联网上的一个小角落,它可以教您和我有关不同算法的概念,并分解算法的基本工作方式。 所有这些都将使用ES6格式的Javascript。

DISCLAIMER: I AM NO EXPERT AND STILL LEARNING. If you find an error in my algorithm or math please let me know and let it be a teachable moment rather than a sarcastic or self-righteous one.

免责声明:我不是专家,而且仍在学习。 如果您发现我的算法或数学错误,请告诉我,并且这应该是一个可教的时刻,而不是讽刺或自以为是的时刻。

Today, I will be covering the natural structure of nature, the fibonacci sequence, and how to get the nth fibonacci. I know I promised a binary tree problem, but I found learning some Dynamic Programming principles important, so I thought I would share.

今天,我将介绍自然的自然结构,斐波那契数列以及如何获得第n个斐波那契。 我知道我答应过二叉树问题,但是我发现学习一些动态编程原理很重要,因此我想与大家分享。

斐波那契数列是什么? (What is the Fibonacci sequence?)

The Fibonacci sequence is a series of numbers that have a special relationship to each the prior two numbers. The math behind it is essentially the sum of the two prior numbers in the sequence equals the current number. For example, lets set Fibonacci Sequence to f, and any place in the sequence is n, if we want to get f(nth place) we would add f(n-1) and f(n-2). Mathematically, it would look like f(n-2)+f(n-1)=f(n). Remember this, it is important! Let’s look at the first few numbers in the sequence and get an understanding.

斐波那契数列是一系列数字,它们与之前的两个数字都有特殊的关系。 它背后的数学运算本质上是序列中两个先前数字的总和,等于当前数字。 例如,将斐波那契数列设置为f,序列中的任何位置为n,如果要获得f(第n位),则将f(n-1)和f(n-2)相加。 从数学上讲,它看起来像是f(n-2)+ f(n-1)= f(n)。 记住这一点,很重要! 让我们看一下序列中的前几个数字并获得理解。

Image for post

We have 2 base cases to start our sequence off. 0 and 1, and after that the magic happens. Note: Sometimes they will start with 1, but I like to start with 0, it is personal preference. Basically, the current f(n) shifts over to f(n-1), and f(n-1) becomes f(n-2), and the cycle continues.

我们有2个基本案例来开始我们的序列。 0和1,然后魔术发生了。 注意:有时它们将从1开始,但是我喜欢从0开始,这是个人喜好。 基本上,电流f(n)转换为f(n-1),f(n-1)变为f(n-2),并且循环继续进行。

问题 (Problem)

The Fibonacci sequence is defined as follows: the first number of the sequence is 0, the second number is 1, and the nth number is the sum of the (n-1)th and (n-2)th numbers. Write a function that takes in an integer n and returns the nth Fibonacci number.(In non-math terms, take a number and return at what number comes back in the sequence at that count.)

斐波那契数列定义如下:该数列的第一个数字为0,第二个数字为1,第n个数字是第(n-1)个和第(n-2)个数字的和。 编写一个接受整数n并返回第n个斐波那契数的函数(在非数学术语中,取一个数字并返回该次数后该序列返回的数字)。

Important note: the Fibonacci sequence is often defined with its first two numbers as F0 = 0 and F1 = 1. For the purpose of this question, the first Fibonacci number is F0; therefore, getNthFib(1) is equal to F0, getNthFib(2) is equal to F1, etc..

重要说明:斐波那契数列通常用前两个数字定义为F0 = 0和F1 = 1。 因此,getNthFib(1)等于F0,getNthFib(2)等于F1,依此类推。

Sample

样品

n = 2f(1) = 0
f(2) = 1Answer is f(2)'s value or 1n = 6f(1) = 0
f(2) = 1
f(3) = 1
f(4) = 2
f(5) = 3
f(6) = 5

(Solution)

There are 2 ways we are going to solve this problem. The straight recursive method and the memoized recursive method.

有两种方法可以解决此问题。 直接递归方法和记忆式递归方法。

方法1递归 (Method 1 Recursion)

const getNthFib = (n) => {
if(n === 1) return 0
if(n === 2) return 1
return getNthFib(n-1) + getNthFib(n-2)
}

Key Element(s) of Method 1

方法1的关键要素

Recursion: Welcome to Dynamic Programming! Recursion is a thing that really freaks people out. It is basically the function calling itself. Whoa Whoa Whoa! How can it call itself if the function is still running?!!? The short of it is that this new sub-function or subroutine will run and put the function it was called in on hold. This is especially true of single-threaded languages like javascript. But how do end this continuous function call and not end up with an infinity paradox a la stack overflow? We use something called a base case that you set which stops the recursion calls. This will then trigger all the subroutines to return the data to the function below it on the stack until you reach the original function where you return all the computational data each subroutine/sub-function did and have your answer.

递归:欢迎使用动态编程! 递归确实使人们感到恐惧。 它基本上是调用自身的函数。 哇哇哇! 如果该函数仍在运行,如何调用自身?!? 简而言之,这个新的子函数或子例程将运行并保留被调用的函数。 对于单线程语言(例如javascript)尤其如此。 但是,如何结束这个连续的函数调用,而又不因无限悖论而导致堆栈溢出呢? 我们使用您设置的称为基本案例的东西来停止递归调用。 然后,这将触发所有子例程将数据返回到堆栈中其下的函数,直到到达原始函数为止,在该函数中您将返回每个子例程/子函数所做的所有计算数据并获得答案。

What is happening in the code?

代码中发生了什么?

Image for post
What a recursive gentleman
多么一位递归绅士

We will be going through the whole function recursive calls and all! I will draw it out so we can make sense of it visually!

我们将遍历整个函数以及所有递归调用! 我将其绘制出来,以便我们可以从视觉上理解它!

f(6) = f(5) + f(4) and recursion go!

f(6)= f(5)+ f(4),然后递归!

Image for post
It took me way to many tries to get it this neat
我花了很多精力来做到这一点

We can see that our base cases of f(1) returns 0 and f(2) returns 1. When it gets all passed up we are adding it up. I would recommend drawing it out the same way I did so you can get a sense of how fibonacci works with recursion.

我们可以看到f(1)的基本情况返回0,f(2)返回1。当所有结果均传递时,我们将其相加。 我建议以与我相同的方式来绘制它,以便您可以了解斐波那契如何与递归一起工作。

However, this is a lot of work! As the old adage goes ‘Work smart, not hard!’ Why do we need to keep calling the same recursive calls on the same repeating f(n)’s. If only there was some way to store that data with a quicker run time and SOBO(Save Our Big O)

但是,这是很多工作! 正如古老的格言所说的那样:“聪明地工作,而不是努力!” 为什么我们需要在相同的重复f(n)上继续调用相同的递归调用。 如果只有某种方法可以以更快的运行时间和SOBO(Save Our Big O)存储数据

方法2:记忆和递归 (Method 2 Memoize and Recursion)

const getNthFib = (n, cache = {1:0, 2:1}) => {
if(n in cache){
return cache[n]
} else {
cache[n] = getNthFib(n-1)+getNthFib(n-2);
return cache[n]
}
}

Key Element(s) of Method 2

方法2的关键要素

Memoization: Memoization is using an object to store an input and out. The input would be the key and the output would be the value. The one caveat to this is we have to make sure our input and output are consistent no matter the number(s) we plop into the given function. This is super helpful because it gives a run time of O(1) when we are looking up something we have already seen.

备注:备注使用对象存储输入和输出。 输入将是键,而输出将是值。 需要注意的一个问题是,无论输入给定函数的数量是多少,我们都必须确保输入和输出是一致的。 这非常有用,因为当我们查找已经看到的内容时,它的运行时间为O(1)。

What is happening in the code?

代码中发生了什么?

Here’s a deep cut
这是一个深切

We have added a cache/hash/memoize to our function! This helps us by storing values we have seen before and making them accessible really quickly. We have to populate it with our base cases though. If you recall in the beautiful recursive drawing above, we are calling the same things over and over again, when we have already seen it. If we store what we have seen before it will end up looking more like this:

我们在功能中添加了缓存/哈希/存储! 这可以通过存储我们之前看到的值并使其真正快速可访问来帮助我们。 但是,我们必须用基本案例来填充它。 如果您回想起上面漂亮的递归图中,当我们已经看到相同的内容时,我们会一遍又一遍地调用相同的内容。 如果我们存储之前看到的内容,它将最终看起来像这样:

Image for post
New and Improved!
新功能和改进功能!

See how many steps that cuts out, because we can now access it on our cache?!?! This is why I love programming! HAWT DAMN! Our cache will look like this at the end:

看看削减了多少步骤,因为我们现在可以在缓存中访问它了!!?! 这就是为什么我喜欢编程! 真该死! 最后,我们的缓存如下所示:

cache = {
1: 0,
2: 1,
3: 1,
4: 2,
5: 3,
6: 5
}

Just a re-usable and faster way to access fibonacci’s sequence, once we have seen the f(n) already.

一旦我们已经看过f(n),那是访问斐波那契数列的一种可重用和更快的方法。

Important Note:

重要的提示:

When we want to pass along something like a cache down a recursive function, we should pass it as an argument. If we create the cache in the original function with let, const, or var declaration, and then add something to the cache, when we call the function recursively and enter the new sub-function, it will reset to the original cache declared in the OG function.

当我们想将诸如高速缓存之类的内容传递给递归函数时,应将其作为参数传递。 如果我们使用let,const或var声明在原始函数中创建缓存,然后向缓存中添加一些内容,则当我们递归调用该函数并输入新的子函数时,它将重置为在OG功能。

时间/空间复杂度 (Time/Space Complexity)

Method 1:

方法1:

Our time complexity is O(2^n) because with each recursive call we are calling 2 more functions, unless we hit a base case on one of the recursive calls.

我们的时间复杂度为O(2 ^ n),因为每次递归调用都会调用另外2个函数,除非我们在其中一个递归调用上遇到了一个基本情况。

Our space complexity is O(n) because and this is important in recursion we are using the call stack(remember the plates) and that takes up memory. The stack is a data structure so it uses memory n times, where n is the number of recursive calls.

我们的空间复杂度为O(n),因为在递归中很重要 ,因为我们正在使用调用堆栈(记住板),并且占用了内存。 堆栈是一种数据结构,因此它使用n次内存,其中n是递归调用的数量。

Method 2:

方法2:

Our time complexity is O(n) because we are calling each recursive case at least once before it gets added to the cache.

我们的时间复杂度为O(n),因为我们在将每个递归案例添加到缓存之前至少调用一次。

Our space complexity is O(n) because of the same reason as method 1, the call stack!

由于与方法1(调用堆栈)相同的原因,我们的空间复杂度为O(n)

下次在Algo Corner (Next Time on Algo Corner)

We will be going over Find Three Largest Numbers.

我们将讨论查找三个最大的数字。

The proper way to countdown with your hand. Don’t @ me.
用手倒计时的正确方法。 不要@我。

If you want to learn more about recursion please click this link. HA!

如果您想了解有关递归的更多信息, 请单击此链接 。 哈!

翻译自: https://medium.com/@depakborhara/algo-corner-nth-fibonacci-59e8f19b690c

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值