编程之法:面试和算法心得_算法简介:动态编程

编程之法:面试和算法心得

by Meet Zaveri

通过见面Zaveri

算法简介(第二部分):动态编程 (An intro to Algorithms (Part II): Dynamic Programming)

Suppose you are doing some calculation using an appropriate series of input. There is some computation done at every instance to derive some result. You don’t know that you had encountered the same output when you had supplied the same input. So it’s like you are doing re-computation of a result that was previously achieved by specific input for its respective output.

假设您正在使用适当的输入序列进行一些计算。 每个实例都要进行一些计算以得出一些结果。 当您提供相同的输入时,您不知道遇到了相同的输出 。 因此,就像您正在重新计算先前通过特定输入为其相应输出实现的结果一样。

But what’s the problem here? Thing is that your precious time is wasted. You can easily solve the problem here by keeping records that map previously computed results. Such as using the appropriate data structure. For example, you could store input as key and output as a value (part of mapping).

但是这里有什么问题? 事情是您的宝贵时间被浪费了。 您可以通过保留映射先前计算结果的记录来轻松解决此问题。 例如使用适当的数据结构。 例如,您可以将输入存储为键,将输出存储为值(映射的一部分)。

Those who cannot remember the past are condemned to repeat it. ~Dynamic Programming
那些不记得过去的人会被谴责重复过去。 〜动态编程

Now by analyzing the problem, store its input if it’s new (or not in the data structure) with its respective output. Else check that input key and get the resultant output from its value. That way when you do some computation and check if that input existed in that data structure, you can directly get the result. Thus we can relate this approach to dynamic programming techniques.

现在,通过分析问题,如果输入是新的(或不在数据结构中),则将其输入与其各自的输出一起存储。 否则,检查该输入键并从其值获取结果输出。 这样,当您进行一些计算并检查该输入是否存在于该数据结构中时,就可以直接获得结果。 因此,我们可以将此方法与动态编程技术联系起来。

进入动态编程 (Diving into dynamic programming)

In a nutshell, we can say that dynamic programming is used primarily for optimizing problems, where we wish to find the “best” way of doing something.

简而言之,我们可以说动态编程主要用于优化问题,我们希望找到解决问题的“最佳”方法。

A certain scenario is like there are re-occurring subproblems which in turn have their own smaller subproblems. Instead of trying to solve those re-appearing subproblems, again and again, dynamic programming suggests solving each of the smaller subproblems only once. Then you record the results in a table from which a solution to the original problem can be obtained.

某种情况就像有重复出现的子问题,而子问题又有自己的子问题。 动态编程不是一次又一次地解决那些再次出现的子问题,而是建议每个较小的子问题只解决一次。 然后,将结果记录在一个表中,从中可以获取原始问题的解决方案。

For instance, the Fibonacci numbers 0,1,1,2,3,5,8,13,… have a simple description where each term is related to the two terms before it. If F(n) is the nth term of this series then we have F(n) = F(n-1) + F(n-2). This is called a recursive formula or a recurrence relation. It needs earlier terms to have been computed in order to compute a later term.

例如, 斐波那契数 0,1,1,2,3,5,8,13,…具有简单的描述,其中每个术语都与其之前的两个术语相关。 如果F(n)是该系列的第n个项,则我们有F(n) = F(n-1) + F(n-2) 。 这称为递归公式递归关系。 需要先计算出较早的项才能计算出较新的项。

The majority of Dynamic Programming problems can be categorized into two types:

大多数动态编程问题可以分为两种类型:

  1. Optimization problems.

    优化问题。

  2. Combinatorial problems.

    组合问题。

The optimization problems expect you to select a feasible solution so that the value of the required function is minimized or maximized. Combinatorial problems expect you to figure out the number of ways to do something or the probability of some event happening.

优化问题要求您选择一个可行的解决方案,以使所需功能的值最小化或最大化。 组合问题要求您弄清楚做某事的方式数量或某些事件发生的可能性。

解决方法:自上而下与自下而上 (An approach to solve: top-down vs bottom-up)

There are the following two main different ways to solve the problem:

解决问题的方法主要有以下两种:

Top-down: You start from the top, solving the problem by breaking it down. If you see that the problem has been solved already, then just return the saved answer. This is referred to as Memoization.

自上而下:您从头开始,通过分解来解决问题。 如果您发现问题已经解决,则只需返回保存的答案即可。 这称为“ 备忘”。

Bottom-up: You directly start solving the smaller subproblems making your way to the top to derive the final solution of that one big problem. In this process, it is guaranteed that the subproblems are solved before solving the problem. This can be called Tabulation (table-filling algorithm).

自下而上:您可以直接开始解决较小的子问题,从而直达顶端,以得出该大问题的最终解决方案。 在此过程中,可以确保在解决问题之前先解决子问题。 这可以称为制表 ( 表格填充算法 )。

In reference to iteration vs recursion, bottom-up uses iteration and the top-down uses recursion.

关于迭代与递归,自下而上使用迭代,而自上而下使用递归。

Here there is a comparison between a naive approach vs a DP approach. You can see the difference by the time complexity of both.

这里有一个天真的方法与DP方法之间的比较。 您可以通过两者的时间复杂度看到差异。

备注:不要忘记 (Memoization: Don’t forget)

Jeff Erickson describes in his notes, for Fibonacci numbers:

Jeff Erickson在他的笔记中描述了斐波那契数:

The obvious reason for the recursive algorithm’s lack of speed is that it computes the same Fibonacci numbers over and over and over.
递归算法缺乏速度的明显原因是,它一遍又一遍地计算相同的斐波那契数。

We can speed up our recursive algorithm considerably just by writing down the results of our recursive calls. Then we can look them up again if we need them later.

只需写下递归调用的结果,就可以大大加快递归算法的速度。 然后,如果以后需要它们,我们可以再次查找它们。

Memoization refers to the technique of caching and reusing previously computed results.

备注是指缓存和重用先前计算的结果的技术。

If you use memoization to solve the problem, you do it by maintaining a map of already solved subproblems (as we earlier talked about the mapping of key and value). You do it “top-down” in the sense that you solve the “top” problem first (which typically recurses down to solve the sub-problems).

如果使用备忘录来解决问题,则可以通过维护已经解决的子问题的映射来实现(如我们之前所讨论的键和值的映射 )。 你这样做,你首先解决“顶”的问题(这通常递归下降解决子问题)“ 自上而下 ”的感觉。

Pseudocode for memoization:

用于记忆的伪代码

So using recursion, we perform this with extra overhead memory (i.e. here lookup) to store results. If there is a value stored in the lookup, we return it directly or we add it to lookup for that specific index.

因此,使用递归,我们将使用额外的开销内存(即此处的查找)来执行此操作以存储结果。 如果在查询中存储了一个值,我们将其直接返回,或者将其添加到该特定索引的查询中。

Remember that there is a tradeoff of extra overhead with respect to the tabulation method.

请记住,在制表方法方面需要权衡额外的开销。

However, if you want more visualizations for memoization, then I suggest looking into this video.

但是,如果您想要更多的可视化内容来进行记忆,那么我建议您观看此视频

表格:以表格形式填写 (Tabulation: Filling up in tabular form)

But once we see how the array (memoized solution) is filled, we can replace the recursion with a simple loop that intentionally fills the array in order, instead of relying on the complicated recursion to do it for us ‘accidentally’.

但是,一旦我们看到数组(内存化的解决方案)是如何填充的,就可以用一个有意地按顺序填充数组的简单循环替换递归,而不必依靠复杂的递归为我们“意外地”完成。

Tabulation does it in “bottom-up” fashion. It’s more straight forward, it does compute all values. It requires less overhead as it does not have to maintain mapping and stores data in tabular form for each value. It may also compute unnecessary values. This can be used if all you want is to compute all values for your problem.

制表以“自下而上”的方式进行。 更直接的是,它确实计算所有值。 由于不需要维护映射并且无需为每个值以表格形式存储数据,因此它需要较少的开销。 它还可能计算不必要的值。 如果您只想计算问题的所有值,则可以使用此方法。

Pseudocode for tabulation:

制表的伪代码:

As you can see pseudocode (right side) in an image, it does iteration (i.e. loops over till the end of an array). It simply starts with fib(0),fib(1),fib(2),… So with the tabulation approach, we can eliminate the need for recursion and simply return the result with looping over elements.

您可以在图像中看到伪代码(右侧),它会进行迭代(即循环到数组的末尾)。 它只是以fib(0),fib(1),fib(2)开头,因此,通过列表方法,我们可以消除对递归的需要,并通过循环元素简单地返回结果。

回顾历史 (Looking back in history)

Richard bellman was the man behind this concept. He came up with this when he was working for RAND Corporation in the mid-1950s. The reason he chose this name “dynamic programming” was to hide the mathematics work he did for this research. He was afraid his bosses would oppose or dislike any kind of mathematical research.

理查德·贝尔曼(Richard Bellman)是这个概念的幕后推手。 在1950年代中期为RAND Corporation工作时,他想到了这一点。 他之所以选择这个名称为“动态编程”,是为了隐藏他为这项研究所做的数学工作。 他担心老板会反对或不喜欢任何数学研究。

Okay, so the word ‘programming’ is just a reference to clarify that this was an old-fashioned way of planning or scheduling, typically by filling in a table (in a dynamic manner rather than in a linear way) over the time rather than all at once.

好的,所以“编程”一词只是为了澄清这是一种老式的计划或调度方式,通常是在一段时间内(以动态方式而不是以线性方式)填充表格,而不是一次全部。

结语 (Wrapping up)

That’s it. This is part 2 of the algorithm series I started last year. In my previous post, we discussed about what are searching and sorting algorithms. Apologies that I couldn’t deliver this in a shorter time. But I am willing to make things faster in the coming months.

而已。 这是我去年开始的算法系列的第2部分。 在我以前的文章中 ,我们讨论了什么是搜索和排序算法。 抱歉,我无法在较短时间内提供。 但我愿意在未来几个月内加快速度。

Hope you liked it and I’ll be soon looking to add a third one in the series soon. Happy coding!

希望您喜欢它,我会尽快在系列中添加第三个。 编码愉快!

Resources:

资源:

Introduction to Dynamic Programming 1 Tutorials & Notes | Algorithms | HackerEarthThe image above says a lot about Dynamic Programming. So, is repeating the things for which you already have the…www.hackerearth.comCommunity — Competitive Programming — Competitive Programming Tutorials — Dynamic Programming: From…Community — Competitive Programming — Competitive Programming Tutorials — Dynamic Programming: From Novice to Advancedwww.topcoder.com

动态编程简介1教程和注释| 算法| HackerEarth 上面的图片充分说明了动态编程。 因此,在重复您已经拥有的东西 。www.hackerearth.com 社区-竞争编程-竞争编程教程-动态编程:从……开始 社区-竞争编程-竞争编程教程-动态编程:从新手到高级 www。 topcoder.com

https://www.geeksforgeeks.org/overlapping-subproblems-property-in-dynamic-programming-dp-1/

https://www.geeksforgeeks.org/overlapping-subproblems-property-in-dynamic-programming-dp-1/

Special props to Jeff Erickson and his notes for algorithm — http://jeffe.cs.illinois.edu/

杰夫·埃里克森(Jeff Erickson)及其算法注释的特殊道具-http: //jeffe.cs.illinois.edu/

翻译自: https://www.freecodecamp.org/news/an-intro-to-algorithms-dynamic-programming-dd00873362bb/

编程之法:面试和算法心得

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值