编程初学者
Dynamic Programming is a very popular algorithmic approach in competitive programming. Dynamic Programming which is abbreviated as DP is one of the most important topics both in the context of programming competitions as well as in the coding interviews of many big tech giants like Amazon, Google, Microsoft, Facebook and so on..This article is focussed on how to identify a DP problem by taking examples of some very popular DP problems.
动态编程是竞争编程中非常流行的算法方法。 在编程竞赛的背景下以及在许多大型技术巨头(如亚马逊,谷歌,微软,Facebook等)的编码采访中,动态编程(DP)均被称为最重要的主题之一。以一些非常流行的DP问题为例,介绍如何识别DP问题。
什么是DP? (What is DP?)
According to me, DP is an enhanced form of recursion. Recursion along with optimization results in a DP solution. The concept is about remembering and making use of answers to smaller “subproblems” that are already solved.It reduces the time complexity of problems drastically as compared to recursion. Another important observation is that whenever recursion has 2 or more calls, there is a high probability of using DP.
据我说,DP是递归的增强形式。 递归与优化一起产生了DP解决方案。 这个概念是关于记住和利用已解决的较小“子问题”的答案。与递归相比,它大大降低了问题的时间复杂性。 另一个重要的观察结果是,每当递归有2个或更多调用时,使用DP的可能性就很高。
如何识别DP问题? (How to identify a DP problem?)
I personally think that DP is an enhanced form of recursion. While DP at times does seem confusing, I’ve found from personal experience that thinking of solutions and problems recursively makes reaching a DP solution much easier. So, if anybody has a good understanding and knowledge about recursion, he/she can easily solve DP problems. Now coming back to my question about the identification of a DP problem, there are generally 2 ways to identify a DP problem:-
我个人认为DP是递归的增强形式。 尽管有时DP确实令人困惑,但我从个人经验中发现,递归地考虑解决方案和问题使找到DP解决方案变得容易得多。 因此,如果任何人对递归有很好的理解和知识,他/她就可以轻松解决DP问题。 现在回到我关于确定DP问题的问题,通常有两种方法可以识别DP问题:
- Choice Based Problem 基于选择的问题
- Optimal Problems最佳问题
Choice-Based Problems are those problems where there is a choice or option to select a particular object or not. These are situation based problems where there is a choice to consider or reject a particular entity. For example 0–1 Knapsack Problem. The problem is simple. Given a weight and value array of size n consisting of n objects. Here w[i] is the weight of the ith object and val[i] denotes the value of the ith object. You are also given the capacity of the bag W.Your task is to maximize the profit by putting objects in the bag.
基于选择的问题是那些可以选择是否选择特定对象的问题。 这些都是基于情况的问题,可以选择考虑或拒绝特定实体。 例如0–1背包问题。 问题很简单。 给定一个大小为n的权重和值数组,其中包含n个对象。 这里w [i]是第i个对象的权重,而val [i]表示第i个对象的值。 您还将获得袋子的容量。您的任务是通过在袋子中放置物品来最大化利润。
For every object you have to check whether the weight of the object is less than the maximum capacity W. If the weight of the object is greater than W, then it cannot be placed in the bag otherwise you have 2 options-whether to place that object in the bag or reject that object and consider other objects
对于每个物体,您都必须检查物体的重量是否小于最大容量W。如果物体的重量大于W,则不能将其放置在袋子中,否则有2种选择-是否放置放在袋子里或拒绝该物品并考虑其他物品
if(w1>W) — Reject
if(w1> W)—拒绝
if(w1<W) — Reject or Accept (Choice is there)
if(w1 <W)—拒绝或接受(有选择)
I am not going deep in the Knapsack problem and not further going to solve this problem which I may do later at some point in time but my only aim here was to expose you to such situations where you have to make choices.I hope it is clear to you.
我不会深入研究背包问题,也不会进一步解决这个问题,我稍后可能会在某个时候做,但是我的唯一目的是让您了解必须做出选择的情况。对你清楚。
Optimal problems are those problems where you have to find an optimal solution -largest/smallest/maximum/minimum etc.
最佳问题是那些您必须找到最佳解决方案的问题-最大/最小/最大/最小等。
Let's take the example of the Longest Common Subsequence of 2 strings. This is a very classical DP problem where you have to find the longest common subsequence.
让我们以2个字符串的最长公共子序列为例。 这是一个非常经典的DP问题,您必须找到最长的公共子序列。
Take the following input
进行以下输入
6 6ABCDGHAEDFHR
6 6ABCDGHAEDFHR
The LCS of the above two strings is “ADH” and its length is 3.
以上两个字符串的LCS为“ ADH”,长度为3。
Simple recursive code for the above problem is
用于上述问题的简单递归代码是
int LCS(string x,string y, int n,int m){if(n==0 || m==0) return 0;if(x[n-1]==Y[m-1])return 1+LCS(x,y,n-1,m-1);elsereturn max(LCS(x,y,n-1,m),LCS(x,y,n,m-1));}
int LCS(string x,string y,int n,int m){if(n == 0 || m == 0)返回0; if(x [n-1] == Y [m-1])return 1 + LCS(x,y,n-1,m-1); elsereturn max(LCS(x,y,n-1,m),LCS(x,y,n,m-1));}
Recursion is the parent of DP. Recursive code can be converted into a DP solution by memoization. Memoisation is mainly used to overcome the issue of recomputing the same problems again and again which is also known as overlapping problems and stores the solution to a particular input. If the same input is again later called then we don’t have to solve it again and we can easily fetch this data from already stored results. For the implementation of memorization, we make a table or a matrix and store the results in it.
递归是DP的父级。 可以通过记忆将递归代码转换为DP解决方案。 记忆化主要用于克服一次又一次地重新计算相同问题的问题,这又称为重叠问题并将解决方案存储到特定输入。 如果以后再次调用相同的输入,则我们不必再次解决它,并且可以轻松地从已存储的结果中获取此数据。 为了实现记忆,我们制作了一个表或一个矩阵并将结果存储在其中。
DP code for LCS is:
LCS的DP代码为:
int main(){
int main(){
Input m,n,x,y
输入m,n,x,y
int t[n+1][m+1]; //Matrix Creation
int t [n + 1] [m + 1]; //创建矩阵
memset(t,-1,sizeof(t));//Initialisation
memset(t,-1,sizeof(t)); //初始化
LCS(x,y,n,m);
LCS(x,y,n,m);
}
}
int LCS(string x,string y,int n,int m){if(n==0 || m==0) return 0;if(t[n][m]!=-1)return t[m][n];if(x[n-1]==Y[m-1])t[n][m]=1+LCS(x,y,n-1,m-1);elset[n][m]=max(LCS(x,y,n-1,m),LCS(x,y,n,m-1));}
int LCS(string x,string y,int n,int m){if(n == 0 || m == 0)返回0; if(t [n] [m]!=-1)返回t [m ] [n]; if(x [n-1] == Y [m-1])t [n] [m] = 1 + LCS(x,y,n-1,m-1); elset [n ] [m] = max(LCS(x,y,n-1,m),LCS(x,y,n,m-1));}
Hope this article gives you a slight idea about DP and how it can be identified. I wish in the future I may post articles on how to convert a recursive solution into a DP solution.
希望本文能使您对DP及其识别方法有个大概的了解。 我希望将来能发表有关如何将递归解决方案转换为DP解决方案的文章。
Stay tuned!!
敬请关注!!
翻译自: https://medium.com/nerd-for-tech/dynamic-programming-for-beginners-1ac099816b0e
编程初学者