python初学者编程指南_动态编程初学者指南
python初學者編程指南
編程輔導 (PROGRAMMING TUTORIAL)
Dynamic programming is an art, the more problems you solve easier it gets.
動態編程是一門藝術,您解決的問題越多,它越容易獲得。
Sometimes when you write code it might take some time to execute or it may never run even if your logic is fine. The same problem occurred to me while solving Google Foobar challenge questions and I realized that the solution was not optimized and was using all available RAM (for large values).
有時,即使您的邏輯還不錯,在編寫代碼時也可能需要花費一些時間才能執行或永遠無法運行。 在解決Google Foobar挑戰性問題時,我遇到了同樣的問題,我意識到該解決方案并未進行優化,并且正在使用所有可用的RAM(用于大數值)。
An entirely different approach is required to solve such kinds of problems i.e. “optimization of code” by following the concept of dynamic programming.
通過遵循動態編程的概念,需要一種完全不同的方法來解決這類問題,即“代碼優化” 。
什么是動態編程? (What is Dynamic Programming?)
Dynamic programming is a terrific approach that can be applied to a class of problems for obtaining an efficient and optimal solution.
動態編程是一種極好的方法,可以將其應用于一類問題,以獲取有效且最佳的解決方案。
In simple words, the concept behind dynamic programming is to break the problems into sub-problems and save the result for the future so that we will not have to compute that same problem again. Further optimization of sub-problems which optimizes the overall solution is known as optimal substructure property.
簡而言之,動態編程的概念是將問題分解為子問題并保存結果以備將來使用,這樣我們就不必再次計算相同的問題。 優化整體解決方案的子問題的進一步優化稱為最佳子結構屬性。
Two ways in which dynamic programming can be applied:
可以應用動態編程的兩種方式:
自頂向下: (Top-Down:)
In this method, the problem is broken down and if the problem is solved already then saved value is returned, otherwise, the value of the function is memoized i.e. it will be calculated for the first time; for every other time, the stored value will be called back. Memoization is a great way for computationally expensive programs. Don’t confuse memoization with memorize.
用這種方法可以解決問題,如果問題已經解決,則返回保存的值,否則將記憶該函數的值,即將首次計算該值。 每隔一段時間,存儲的值將被調回一次。 記憶化是計算昂貴的程序的好方法。 不要將記憶與記憶混淆。
Memoize != memorize
記住!=記住
自下而上: (Bottom-Up:)
This is an effective way of avoiding recursion by decreasing the time complexity that recursion builds up (i.e. memory cost because of recalculation of the same values). Here, the solutions to small problems are calculated which builds up the solution to the overall problem. (You will have more clarity on this with the examples explained later in the article).
這是通過減少遞歸建立的時間復雜度(即,由于重新計算相同值而導致的內存開銷)來避免遞歸的有效方法。 在這里,計算出小問題的解決方案,從而建立了整體問題的解決方案。 (您將在本文稍后解釋的示例中對此有更清晰的了解)。
了解在何處使用此技術 (Understanding Where to Use This Technique)
As mentioned above, if you notice that the problem can be broken down into sub-problems and these can be broken into much smaller ones and some of these have overlap (i.e. requires the computation of previously calculated values). The main goal is to optimize the code by reducing the repetition of values by storing the results of sub-problems.
如上所述,如果您注意到問題可以分解為子問題,并且可以分解為小得多的子問題,并且其中一些具有重疊(即需要計算先前計算的值)。 主要目標是通過存儲子問題的結果來減少值的重復,從而優化代碼。
Dynamic Programming can be applied to any such problem that requires the re-calculation of certain values to reach the final solution.
動態編程可以應用于需要重新計算某些值才能達到最終解決方案的任何此類問題。
遞歸和動態編程 (Recursion and Dynamic Programming)
Remember, dynamic programming should not be confused with recursion.
請記住,動態編程不應與遞歸相混淆。
Recursion is a way of finding the solution by expressing the value of a function in terms of other values of that function directly or indirectly and such function is called a recursive function. It follows a top-down approach.
遞歸是通過直接或間接根據該函數的其他值來表達該函數的值來找到解決方案的方法,這種函數稱為遞歸函數。 它遵循自上而下的方法。
Dynamic programming is nothing but recursion with memoization i.e. calculating and storing values that can be later accessed to solve subproblems that occur again, hence making your code faster and reducing the time complexity (computing CPU cycles are reduced).
動態編程不過是帶有記憶的遞歸,即計算和存儲可以稍后訪問以解決再次出現的子問題的值,從而使您的代碼更快并降低了時間復雜度(減少了計算CPU周期)。
Here, the basic idea is to save time by efficient use of space. Recursion takes time but no space while dynamic programming uses space to store solutions to subproblems for future reference thus saving time.
這里的基本思想是通過有效利用空間來節省時間。 遞歸需要時間,但是沒有空間,而動態編程則使用空間來存儲子問題的解決方案以供將來參考,從而節省了時間。
通過示例了解動態編程 (Understanding Dynamic Programming With Examples)
Let’s start with a basic example of the Fibonacci series.
讓我們從斐波那契數列的基本示例開始。
Fibonacci series is a sequence of numbers in such a way that each number is the sum of the two preceding ones, starting from 0 and 1.
斐波那契數列是一個數字序列,每個數字都是從0和1開始的兩個前一個數字的和。
F(n) = F(n-1) + F(n-2)
F(n)= F(n-1)+ F(n-2)
Recursive method:
遞歸方法 :
if n <= 1:
return n
else:
return(r_fibo(n-1) + r_fibo(n-2))
Here, the program will call itself, again and again, to calculate further values. The calculation of the time complexity of the recursion based approach is around O(2?^N). The space complexity of this approach is O(N) as recursion can go max to N.
在這里,程序將一次又一次地調用自身,以計算其他值。 基于遞歸的方法的時間復雜度的計算約為O(2 ^ N)。 此方法的空間復雜度為O(N),因為遞歸可以最大為N。
For example-
例如-
F(4) = F(3) + F(2) = ((F(2) + F(1)) + F(2) = ((F(1) + F(0)) + F(1)) + (F(1) + F(0))
F(4)= F(3)+ F(2)=((F(2)+ F(1))+ F(2)=((F(1)+ F(0))+ F(1) )+(F(1)+ F(0))
In this method values like F(2) are computed twice and calls for F(1) and F(0) are made multiple times. Imagine the number of repetitions if you have to calculate it F(100). This method is ineffective for large values.
在這種方法中,像F(2)這樣的值被計算兩次,并且多次調用F(1)和F(0)。 想象一下如果必須計算重復次數F(100)。 此方法對于較大的值無效。
Top-Down Method
自上而下的方法
if memo[n] != null:
return memo[n]
if n <= 1:
return n
else:
res = fibo(n-1) + fibo(n+1)
memo[n] = res
return res
Here, the computation time is reduced significantly as the outputs produced after each recursion are stored in a list which can be reused later. This method is much more efficient than the previous one.
在這里,由于每次遞歸后產生的輸出都存儲在一個列表中,以后可以重新使用,因此計算時間顯著減少。 這種方法比以前的方法效率更高。
Bottom down
自下而上
if n<=1:
return n
list_ = [0]*(n+1)
list_[0] = 0
list_[1] = 1
for i in range(2, n+1):
list_[i] = list_[i-1] + list[i-2]
return list_[n]
This code doesn’t use recursion at all. Here, we create an empty list of length (n+1) and set the base case of F(0) and F(1) at index positions 0 and 1. This list is created to store the corresponding calculated values using a for loop for index values 2 up to n.
這段代碼根本不使用遞歸。 在這里,我們創建一個長度為(n + 1)的空列表,并在索引位置0和1處設置F(0)和F(1)的基數。創建此列表以使用for循環存儲相應的計算值對于索引值2到n。
Unlike in the recursive method, the time complexity of this code is linear and takes much less time to compute the solution, as the loop runs from 2 to n, i.e., it runs in O(n). This approach is the most efficient way to write a program.
與遞歸方法不同,此代碼的時間復雜度是線性的,并且由于循環從2到n,即以O ( n )運行,因此計算解的時間要少得多。 這種方法是編寫程序的最有效方法 。
Time complexity: O(n) <<< O(2?^N)
時間復雜度:O(n)<<< O(2 ^ N)
Now, let’s see another example (this is an intermediate level problem):
現在,讓我們看另一個示例(這是一個中級問題):
Author) 作者提供照片) Google Foobar Challenge QuestionGoogle Foobar挑戰問題Problem statement: You have to build a staircase in such a way that, each type of staircase should consist of 2 or more steps. No two steps are allowed to be at the same height — each step must be lower than the previous one. All steps must contain at least one brick. A step’s height is classified as the total amount of bricks that make up that step.For example, when N = 3, you have only 1 choice of how to build the staircase, with the first step having a height of 2, and the second step having a height of 1 i.e.(2,1). But when N = 5, there are two ways you can build a staircase from the given bricks. The two staircases can have heights (4, 1) or (3, 2).
問題陳述: 您必須以這樣一種方式構建樓梯,每種樓梯應包含2個或更多步驟。 不允許兩個臺階處于相同的高度-每個臺階都必須低于前一個臺階。 所有步驟必須至少包含一塊磚。 臺階的高度歸為組成該臺階的磚的總量,例如,當N = 3時,您只有一種選擇如何建造樓梯的選項,第一步的高度為2,第二步高度為1 ie(2,1)的臺階。 但是,當N = 5時,有兩種方法可以使用給定的磚塊構建樓梯。 兩個樓梯的高度可以分別為(4,1)或(3,2)。
Write a function called solution(n) that takes a positive integer n and returns the number of different staircases that can be built from exactly n bricks. n will always be at least 3 (so you can have a staircase at all), but no more than 200.
編寫一個稱為solution(n)的函數,該函數采用一個正整數n,并返回可以從正好n個磚塊構建的不同樓梯的數量。 n始終至少為3(因此您可以擁有一個樓梯),但不超過200。
This is a problem I had to solve at level 3 of Google Foobar Challenge. I would suggest you try this question on your own before reading the solution, it will help you understand the concept better.
我必須在Google Foobar Challenge的 第3級上解決這個問題。 我建議您在閱讀解決方案之前自行嘗試這個問題,這將有助于您更好地理解概念。
An intuitive approach to this problem:
解決此問題的直觀方法:
My first intuitive approach was to create a list l of integers till n.
我的第一個直觀方法是創建一個直到n的整數列表l 。
Then append all the possible combinations of integers of list l into a new list sol.
然后將列表l所有可能的整數組合附加到新的列表sol 。
And, at the final step, I used a for loop to check the sum of every element of the list solthat if it is equal to the required value. If the condition is true that element is appended to another new list final. And the length offinal is returned as a final solution to the problem.
并且,在最后一步,我使用了for循環來檢查列表sol中每個元素的和是否等于所需值。 如果條件為true,則將該元素追加到另一個新列表final 。 final的長度將作為問題的最終解決方案返回。
l = []
for i in range(1,n):
l.append(i)
sol = []
for k in range(2,len(l)+1):
for m in combinations(l,k):
sol.append(m)
final = []
for z in (sol):
if sum(z) == n :
final.append(z)
steps = len(final)
return (steps)
solution(100)
This code turned out to be very ineffective and didn’t work for large values because of the same reason i.e. hight time complexity and repeated calculations of certain values. Running this code for large values(like 100) will use all available RAM and code will eventually crash.
事實證明,此代碼非常無效,并且由于相同的原因(即較高的時間復雜度和某些值的重復計算) 而不適用于較大的值。 以較大的值(例如100)運行此代碼將使用所有可用的RAM,并且代碼最終將崩潰。
Bottom-up approach for the same problem:
自底向上方法解決同一問題:
def solution(n):a = [1]+[0]* n
for i in range(1, n+1):
for k in reversed(range(i, n+1)):
a[k] = a[k-i] + a[k]
return a[n] - 1
- At the first step, an empty list ‘a’ is initiated to store all the values from the further loops. 第一步,啟動一個空列表“ a”以存儲來自其他循環的所有值。
After each iteration of the outer loop, a[j] is the number of staircases you can make with height at most i where j is the number of bricks used.
在外循環的每次迭代之后,a [j]是您最多可以在高度i處制作的樓梯數量,其中j是使用的積木數量。
List a is initiated to [1,0,0,...] because there can be only one stair with 0 blocks and 0 height.
列表a起始于[1,0,0,...]因為只能有一個臺階,且臺階數為0,高度為0。
In each iteration of the inner loop, list a is transformed from representing max-height i-1 to representing max-height i, by incorporating the possibility of adding a step of height i to any shorter staircase that leaves you with at least i blocks.
在內部循環的每次迭代中,列表a通過將可能增加高度i的步長加到任何至少使i塊留給您的階梯上的可能性,將列表a從表示最大高度i-1為表示最大高度i 。 。
In the final step, the number of different staircases that can be built from exactly nbricks is returned by the function (1 is subtracted at the end to exclude the case of single stair of height n).
在最后一步中,函數可以返回恰好由n塊磚構成的不同樓梯的數量(最后減去1以排除高度為n的單個樓梯的情況)。
This method is effective for large values as well since the time complexity is traded for space here.
該方法對于大值也有效,因為在此將時間復雜度交換為空間。
This kind of approach can be applied to other problems as well, you just need to identify them and apply the basics of dynamic programming and you will be able to solve the problems efficiently.
這種方法也可以應用于其他問題,您只需要識別它們并應用動態編程的基礎,就能有效解決這些問題。
結論 (Conclusion)
Dynamic programming is a very effective technique for the optimization of code. This technique is really simple and easy to learn however it requires some practice to master.
動態編程是一種用于代碼優化的非常有效的技術。 該技術非常簡單易學,但是需要掌握一些實踐。
“Those who cannot remember the past are condemned to repeat it.”
“那些不記得過去的人應被重述。”
-George Santayana
-喬治·桑塔亞娜(George Santayana)
Dynamic Programming動態編程 Bibliography:https://www.educative.io/edpresso/learn-dynamic-programming-in-10-minuteshttps://www.geeksforgeeks.org/dynamic-programming/https://www.hackerearth.com/practice/algorithms/dynamic-programming/introduction-to-dynamic-programming-1/tutorial/https://www.programiz.com/dsa/dynamic-programming翻譯自: https://towardsdatascience.com/beginners-guide-to-dynamic-programming-8eff07195667
python初學者編程指南
總結
以上是生活随笔為你收集整理的python初学者编程指南_动态编程初学者指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谷歌裁员1.2万人当天 幸存员工崩溃哭泣
- 下一篇: Python中机器学习的特征选择技术