 So, we will do among the last of our recursive examples, which is string edit distance. The problem notation indices were perhaps not set up in enough detail or care last time. So, we will set up the indices and the meaning of everything very clearly. Then we will write recursive code for it. So, the problem was that there is a source string S or in the code called ESSS and that takes on indices of characters between say 1 and n and there is a target string to which I want to transform it. So, I want to go from source to target and T goes from 1 through m say now the question we are asking is what is the smallest number of operations to transform S of 1 through n to T of 1 through m and we call that in the code dist and in symbols just D that is the distance. So, that we call that D of n say m n now so here is the string S here is the string P and to answer that question we first ask what is the last character in each of them. So, the first decision point is whether S n is equal to P of m if that is the case then we look for a smaller problem to solve which is to transform this to that because the last character is already the same. So, in that case my cost will be just D of m minus 1 n minus 1 these are all possibilities I mean even though the last characters are the same the best way to transform S to T may not be to solve that it may well be that this string is much longer and it has an exact match in the prefix and you only append things to that is the best way we do not know that but this is one of the possibilities that you do not pay anything for the last character and we recursively solve smaller problems. The other possibility is that these are not equal and we decide to replace so this is like the option short n each short n all the both the strings in the other case I end up with a recursive cost of 1 plus D m minus 1 n minus 1 this is the replace action. So, I pay one unit for taking this character and replacing it to that character and then I solve the smaller problem recursively that leads to two other cases which is that these are not equal and the way I try to address it is in this case it looks like T is longer. So, maybe what I will decide to do is I will say this is T of 1 through m so I will write down the script as first 1 transform s 1 through n to T 1 through m minus 1 and then append to append T m to T that is a perfectly valid way to build up T from s. So, in that case the cost will be what so there is cost of 1 for appending and the previous cost by definition is D of m minus 1 n the counterpart to that although this string looks longer there may well be a solution where I actually first transform. So, the cost in this case will be the symmetric opposite 1 plus D of m n minus 1 I am trying to translate that into the right steps. So, I transform this part to the whole thing so transform s 1 through n minus 1 to T 1 through m. So, first transform this to the whole string and then drop the last one just ground it you can also do it before the ordering does not really matter delete s m. So, if you wanted to do it in that order then you can say this is step 1 that is step 2 and therefore, the cost is 1 plus D m and n minus 1 fine. So, now there are these four cases the four cases are so short n replace let us give it a name. So, because I am appending something after the transformation let us call that the append option or insert option and this is the delete action. So, now the cost at m n so D m n can be written as the minimum of the four costs. But of course, the first cost applies only if they are equal the last character is equal. So, I will just write that in condition this will be D m minus 1 if so and so 1 plus D m minus 1 with all the action clauses fine. So, every D m n is defined like that recursively in terms of. So, if you think of D as a table as I started out saying will define a special row and column called 0 which will make things easier and then 1 2 up to something 1 2 up to something. Now as I mentioned in the previous lecture if you start with an empty string. So, let us say this is what s is this is what t is. So, this column means s is empty and I want to build up longer and longer t's from empty to empty the cost is obviously 0 and then to build longer t's you have to just keep on appending those characters that is the easiest best way of doing that. So, this row is kind of fixed similarly to take a long s and then truncate it down to 0 you have to get rid of all its characters. So, that will be again 1 2 etcetera. So, the upper and left column and row are easy to decide. Now observe that in the recursion we only look for cells which is 1 to the left or 1 up or both. So, that means that once these two quantities are defined we can fill in the rest of the table or recursively compute D for all the other values. So, that is the setup and the code may have a slight discrepancy in terms of rows and columns, but once you read it offline it should be ok. So, how do I do this? I read in s and t from every 1 and every 2 and then since in c plus plus the default is that the strings first character is at offset 0 which I do not want I wanted to use that band for keeping the base values. So, I insert at position 0 1 character which is some dummy underscore and then similarly with t and then I dist here is an implementation of D. D there implicitly assumes that s and t are like global variables I did not want to do that. So, I am passing s and t explicitly as parameters to dist, but here I am giving the last slot ok there also I am giving the last slot fine and then I am just printing out the distance and finishing up. Now, how does distance work? So, distance takes s and i and t and j. So, remember that they are originally initialized with their own size minus 1. So, I am looking at the last character in the outermost level of recursion. So, depth is again like a previous variable to help us print trace statements properly. Now, here are print statements let me enable the first print statement actually let me do that second later. Now, if i is equal to 0 then I have to return j if j is equal to 0 I have to return i that is the definition of the upper and left bands. Otherwise I initialize best to effectively plus infinity in the integers and if the last characters match s i is equal to t j then we have to shorten both of them ok. So, the recursive call just becomes best of s i minus 1 t and j minus 1 ok. So, map it to m and n as you wish does it really matter and the recursion depth has increased by 1. So, it is 1 plus depth. What is best? So, best has started with infinity and depending on what case I am doing I will keep on taking the minimum of the old best and the next solution. So, best becomes minimum of best and shorter if the last characters do not match then there are these three options deletion, insertion and replacement as we discussed and then those are exactly the calls as I implemented on the board. So, one of the indices goes down to minus 1 and I add 1 or for replacement both the indices go down by 1 and I add minus 1 and I add 1 for the cost of replacement yes. So, this is like a messy c plus plus facility if you will which is if you make a call without giving that last parameter then that default will kick in and you will get depth equal to 0. If you provide it explicitly then that equal to 0 will not take effect. So, now let us compile this. So, if you do that it prints the distance as 3. So, if I happen that it is 5. So, things are now and this should be able to deal with all kinds of things for example, a b c ket n that is 3. I should be able to do ket a b c d e 10 let us see what happens a b c d e. So, it can figure that out today if you are doing insertion deletion anywhere it is good enough to understand the best thing to do. Sometimes you may get unintuitive results it might prepare a problem, but you may not see the shortest edit sequence and then, but this will get the right thing always. Now, let us do one thing which is enable this trace statements to see what kind of recursive calls are happening. First I will enable the trace with the depth. So, you see how the nesting works. Even for very small problems this will get fairly difficult to interpret on screen. Fibonacci was easy permutation was easy this is going to be complicated because in that table any the last element is going to recursively call the previous three those are going to call in all kinds of ways. So, I am going to use the smallest small example here and I have to do less because you will see that huge number of calls will result. So, this 6 7 calls this 5 7 calls this 4 7 etcetera. This is the first place where a base case happens 0 7 you do not need to recurs anymore and then this 1 6 that again calls a base case. So, base cases are 0 with 0's otherwise you keep recursive this enormous space just to compute the edit distance between 6 character string under 7 character string you just keep going and going. The print takes more time than the final answer. So, if you enable the print it just goes on forever lot of recursive calls. And part of the reason is that just like Fibonacci which was repeating computation this is also repeating computation look here is this 0 1 here is this 0 1 here is this 1 1 there is this 1 1. So, the same distance being called multiple times because there are so many paths from m n to any i j. So, some of you know how to compute the number of such paths it is exponential. The number of paths from 0 0 to m n is quite large and that is what is happening all such paths have to accounted for in the recursion. So, suppose you want to actually count it then I am going to disable the indent and just print something with dist and remember that old trick to grape it for dist and pipe it through sort then pipe it through unique. So, edit distance let us do the old example. So, I catch the lines with pattern disk then I sort then I unique it and I list it. So, this 0 0 is called 299 times in each case it returns 0. This 0 1 is called 482 times this is just for a string which is like you know keton and sitting. So, they are all redundant calls because this is a pure function and every time this 0 1 is called it returns us exact same thing. So, you can see the situation and this 6 7 is the last one which is just called once look somewhat similar to Fibonacci and it is exponential the number of calls to lower dist functions. So, this is why in such cases there is other technique called dynamic programming where you realize that your solution has a natural recursive structure, but if you coded it up using pure recursion what would happen is you would reach the same sub problem again and again like Fibonacci. Ideally that Fibonacci tree should have been a we should have common factored all the nodes which were known right. So, to draw you a picture we should not have evaluated them separately. So, suppose Fibonacci of let us pick something manageable and small. So, if I have Fibonacci of say 4 that is Fibonacci of 3 and Fibonacci of 2 this is Fibonacci of 2 and 1 2 is 1 and 0 2 is 1 and 0. So, instead of that massive replication of nodes the correct thing to do would have been that I say line up 0 and 1 I get 2 3 instead of going to that 1 this represent that I do not compute it again I just cache it somewhere and use that value and then 4 uses 3 and 2. So, here every node appears exactly once. So, this means that I am reusing old values without computing them and spreading them out into a tree. So, I would like to do similar things with edit distance as well and the way to do that is to just naturally make the disk from a function into a table into a 2D matrix. So, this is what I started out the class with I am going to actually make an array out of it a 2D matrix rather. So, that is the transformation problem I have to convert s 1 through n into t 1 through m now the indexing will be consistent. So, here is the 2D array I will build the array will be called dist it will go from 0 to m and 0 through n it will represent the source matrix and the index j will go across this will represent the target string and the index i will go down this will be filled with 0 through m that will be filled 0 through n to start with and the rest is pretty obvious. So, instead of writing a recursive routine I will actually write a small function to fill in this array and finally, just reading of this value will give me the array distance. So, that is clear enough. Now, what else do I have to do? If I have to actually tell you how to edit s to turn it into t or I have to draw that yellow path which is the best path through this array then I also have to maintain a record of the action I took. So, there will be a second array apart from this which will be called action and action along the upper and left bands is nothing there is no action or rather you could think of it as I do not need to know because I really insert and delete, but it does not really matter. So, anyway there are 4 kinds of actions there is shortened insert delete and replace. Now, I could of course in C plus plus I could say that well arbitrarily let shortened be represented by integer 0 this by integer 1. So, I have this array with this 4 values but the problem is that you know tomorrow if you find some other new action and you try to you know someone else is writing or updating your code this the code meaning can change and what you insert into the array is hidden deep inside your code and it is just an integer which is taken to a matrix. It is generally bad to have magic integers inside your code unless the integers are obvious ones like index minus 1 or index times 2 things like that or 2 to the power p those kinds of constants are ok, but if you have an arbitrary association between values in your model world and you are turning that integers it is much better to use construct that is provided in both C plus plus and Java it is called a enumeration although the support in C plus plus is not great. So, the way to code that is to say enum and then give you give the name of a type this will become a type and then inside by convention it those are written in uppercase. So, you can say shortened insert delete and replace. So, what does this statement do? It defines a new type called action it is like the system had int card bool float double now the system knows of a new type called action it is secretly an int, but you do not need to really know that yet. Now if you are writing some function you can now say action act and other parameters you can even return action from the function you can declare a variable called act you know of type action and you are in the code if you print it out you will get an integer. So, that is the bad part Java fixes that. So, in fact what C plus plus will do is that it will secretly assign this 0 it will assign this 1 it will assign this 2 it will assign this 3, but the advantage is that if now you decide that you need a no action none you insert that and then numbering changes none becomes 0 this becomes 1 automatically you do not need to reassign the numbers by hand make a mistake. And inside the code you could always say action act 2 equals say none. So, you should not use an integer you should really use that symbolic variable or constant rather. So, that the right value goes into the variable. So, that is so what we will have is we will declare action to be a matrix of action no they are just symbolic names. So, what is the action you have to do at a point i j to proceed which of the four choices give me the best solution for i j I just record that. So, let us look at the non recursive code yes. So, in C plus plus again just like bool enum is a syntactic comfort that is given to you, but internally enum values are represented as ints. So, you can freely assign between enums and ints and no one is any wiser you print an enum variable you get an integer output. So, that is pretty bad. So, in Java enums really define a new type even internally and when you print in Java if you printed short end you would actually get the string short end on screen you do not get 0. And you cannot inter assign between integers and enums. So, you should not write case 1 case 2 you should say case short end case insert. Yes, you will compile correctly that is the point. So, switch is a prominent use of enums. So, here goes. So, array distance 2 defines this action none short end delete insert replace and very often to print this out properly programmers use the same set of the following device although I will not discuss it today in much detail. So, it will say car star action strings. So, once you have that you can use an action variable to index into this array and print the correct string and you keep these two declarations side by side. So, that anyone updating one of them has to update the other as well otherwise there will be a bug, but let us not worry about that the important thing is to look at the action definition it is just a bunch of integers, but with symbolic names. So, that we can write code more cleanly and readably. So, print is about the same as before except that along the left and upper spine I print the strings s and t also. So, that we can see what is happening in the array just like I did in the slide over here. So, we actually print sitting and kitter along the upper and left edges. So, main here it is not recursive. So, I have put the whole code inside main s, t are read as before I insert the dummy character at the beginning as before remember rows correspond to t and columns correspond to s. So, I have this two matrices one is the disk matrix taking the place of the recursive function. So, that I can reuse values and there is a matrix of actions which is called action the same size as disk. Now, along the let us see. So, one thing I could do is I could say disk 00 equal to 0 and action 00 equal to none you do not need any action to turn an empty string into an empty string. Otherwise, for ix equal to 1 to disk dot size. So, remember what is going on here ix is down the rows. So, I am growing the target by inserting on an empty string. So, I say something like action ix 0 equal to insert whereas here jx goes across. So, there I have to delete to bring it to an empty target. So, here and now I start the job of filling in the inner cells of the two arrays and the code is about the same as before now i and j start from one each. So, I am inside the region I initialize best to infinity if t ix is equal to s jx then I have a shorter problem. So, I look up this is not a recursive call anymore I am just looking up entries in the matrix which have already been settled. And if I can improve my best solution then I record the best solution, but I also remember the action. So, action ij will be shorter otherwise if the last two characters are not the same. So, in that two fold plan let me get the convention right otherwise let us finish of the replacement then come back to insert and delete and really do that correctly right way around. So, replacement is where the last characters are not the same and I solve a smaller problem and I pay one unit for the replacement. If that is the best it is replacement is better than best then I set action to replace. Now, in these two cases what is happening if I say dist of say I think I have got it opposite dist of no i and j minus 1. So, that means I deleted something of the end of s j goes along the top right. So, that is the delete option otherwise if it is i minus 1 and j then after the end I have to insert something at the end of t after the recursive transformation is done. So, this is ok fine. So, each cell action ij will hold one of shorten insert delete and replace and then at the end of it I will print this itself and I will separately print action. So, let us see how that ends up 11 is that funny statement I am just going to get rid of it. So, Kitten and sitting so this is what we get. So, to turn an empty string into sitting takes those costs to turn that string into empty string takes that cost and then as you can see the final cost is 3. So, how do we get all that and then this is the action that is printed separately. Now, this is the problem that this is not printing insert delete it is printing integers. If I wanted to print the strings then I have to look through that indirection array and do the right thing. I mean look at that string array and then print the strings. But let us try to remember what is going on here. So, I am just going to put a comment so I can quickly look up. So, see in this this vertical this is none no action required empty to empty this vertical spine is one of insertions. So, insert is 3 that is a bunch of deletions to get to the empty string. So, that is delete and inside here are various possibilities. So, the last thing here tells me that I have to do a insert. What do I have to insert? I have to insert G. Now, if I took the insert path then remember from the code that insertion happens when I the my recursive call is I minus 1 and J. So, I record insert only if I if the recursive call was I minus 1 and J. So, in other words because this was an insert I have 2 3 and 2 here. So, this tells me that this action was insert. So, I have to drop down to the next cell where the cost was 2 and that last insertion of G cost me 1 that is how I went from 2 to 3. Now, I go to this cell and the action there was 1 which was when do I put in an action of 1 which is shortened. Shortened means the last characters were the same. So, both are shortened. So, if this was 1 that means from 2 I have to go to here and the cost should be the same because the last two characters are same n is equal to n. So, can I write a code which traces back from m n and records all the edit operations that I had to make. So, let us try this out. So, suppose we write something like a void trace path where we will put a const matrix int dist and const matrix action. So, I will print out a bunch of things to explain to us what is going on. Now, how do I do this? So, I say for int m equal to that last entry which is dist dot size 1 minus 1 and you can put a comma if you want to define multiple variables this will be dist dot size 2 minus 1. How far do I go? I need to only go as long as m and n are both positive. Otherwise I am done. So, this will be m say greater than 0 and n greater than 0 and the action the changes to m and n will happen inside one or the other may decrease. What do I do inside? Now, this time I have to do a switch on the action in the current cell. So, I say switch act m n and there are 4 cases or 5 cases. None will usually not arise. So, I can just say case short n. I am pretty sure you max as some way to do this automatically. So, there are the 4 cases. Now, if the action is short n then what do I have to do? I have to print out some stuff. So, short n happens only when the characters are the same. So, I will write something like well let me send in the strings as well. So, I will say s that character that was the action and I can step back now. So, what do I do? I do minus minus m minus minus n and so on for the others. So, in case of delete I will say. So, who do I delete from? I delete from s. s is always the target of actions. So, I will say something like delete it is a s. Then I will do minus minus n. Similarly, I could try various things. I hope this is the right convention. If you get wrong it you can fix it. I will and replace is very similar to this. So, now let us see how this works out. At least one of them is decreasing. So, at some point I should stop the loop. This is what? This is trace path. So, trace path is called with s, t, this. Let us see if this compiles is not and if it runs correctly. So, insert t7 equal to g. Shorten n is n. Replace e not i. Replace e i. Then there will be those t's. Kitten and sitting two t's are shared. So, I just have to shorten it. Even i and then replace k not equal to s. So, this is called a back trace. So, whenever you have a dynamic programming like solution you have to keep track of how you got to the solution and this action matrix can help you trace back the path from the final solution toward the initial point. And this sort of gives you a script if you will to turn one string into the other that turns Kitten into sitting. So, any questions about dynamic programming? The first example we will do more. Is the problem totally clear now? So, why did we start with the recursive solution? Because it is very natural to break down such a problem into saying what happened to the last position. Just like factorial says to find n factorial I will just look at the last number n and then appeal to recursion to do the rest of the work for me. So, similarly here given two strings you ask about the last position and then break down the problem into smaller parts. Now, it turned out that recursive implementation was not a good idea because of massive repetition of sub problems. So, we decided to cache the values of the sub problems in a matrix and that made the problem very efficient. By the way, so how much time will this take? If the original strings are m versus n then the time taken to fill in the matrix is proportional to m n. Each cell has only four cases and deals with only its three neighbors. So, to fill in a cell takes constant time, but this quadratic time is still fairly bad. In the sense that on the web corpus if you wanted to detect which page is very similar to which page, not only is it quadratic in the lengths of the two pages you are comparing, but you have to take every two pages from ten billion pages. So, in standard old computer science an algorithm with running time 2 to the power n is bad, an algorithm with running time n factorial is terrible, but an algorithm with running time n cubed is fine, but in the age of web search and processing an algorithm which has time n squared where n is the number of pages is pretty much impractical. So, an interesting problem is that given a web page find the ten pages closest to it say and you do that for all the web pages. So, you realize that the size of the output is ten times ten billion. So, if you add n pages then the required output from is for each page the ten most similar pages. So, the output is really ten times n, but it seems like you have to do n squared comparisons to find those ten n things. So, there are very nice tricks to avoid that and to finish that computation in about n log n time, but that we teach in electric course. So, anyway so string edit distance is important there are many other interesting problems around string edit distance. For example, in genomics a very important problem is given a set of strings find one string whose edit distance to all of them is minimum that is called the centroid string. Just like given a bunch of points the centroid is its arithmetic mean. So, it is like sum of squares of distances is minimized if you do that. It is the mean point you can similarly define medoids or median points. Similarly, for strings now that you have a distance we can start talking about centroid strings. Unfortunately, the centroid string problem is quite complicated. So, anyway those are some of the problems around string processing which are important. Now, let us look at a second actually somewhat simpler example of dynamic program. So, suppose I have a set of numbers and yeah and now I ask is there a subset that adds up to say S where S is a given in these all integers then find report the subset otherwise report that there is no such subset. So, how are you going to do this and imagine just for simplicity assume that all the numbers are distinct. So, it is a real set. So, any ideas? So, again think of the last position or something. So, suppose there is a subset that adds up to S each element a i is either in it or it is not in it. So, the way I will set up the recursion and then do dynamic programming is. So, it always helps to start out thinking recursively and then if you feel that sub problems are massively shared or replicated you should implement it as dynamic program. So, the question I ask is is a n. So, let us say the sum is say a and the subset is S change the symbol. Is a n in S? Suppose yes versus no. If a n is in S then I can create a new problem which is given the elements a 1 through a n minus 1 is there a subset which adds up to S minus n a minus. If no then also I can now only use this, but I still have to make up a with it. So, that is a very simple recursive way of thinking about the problem. And how do we write this recursively? So, remember my eventual answer was supposed to be only a Boolean. Is there a subset or isn't there a subset? What actual subset was picked we can pack in later on through something like that action matrix or whatever. So, I write something like Boole, exist subset. So, this is also a convention for naming things in your code. Generally speaking, Boolean variables and functions should have a verb in their name. Is finished or exist subset. Whereas, other things like quantities should not have verb. They should be noun like phrases. So, in it I will pass a couple of things. What do I pass? The sum I have to target, the vector of int storing the set. It's a constant. I will change it. That should be it actually if I play it right. Let me not pass it by reference. I will actually keep the code like a pure function. That's it. So, in both cases, the set will be shrunk by one. So, I do something like, I don't know if pop back returns the last element. It should, but I'm not sure. I have to look up the manual. So, all I'll do is say that int an is equal to set set dot size minus one. Pop back might do the same thing. But then I'll do set dot pop back to remove that last element. I could probably say int an equal to pop back. So, see both cases, the last element is removed. And now I say return, return what? Return exists subset sum set. Set has been mangled or sum minus an and set. Any one of those cases? Any one of those cases there is a subset exists? The answer is yes. So, it's the order of those two. Except that suppose I want to keep track of what I did. Whether an is in or not? Yes? That is the code. What else do you? That's a good point. So, what is the escape clause? If sum greater than 0, well, if set dot size equal to 0, then if the sum is 0, you have done it. If the sum is not 0, you can't do it. So, return, if the set is empty, then the only sum you can make up is 0. So, if the sum is 0, then you return true. If the sum is not 0, you return false. So, that's the escape clause. Well, what I'm saying is that whether an belongs or not, it will go out of the set anyway. If I pick it as part of the set, then I have to remember this is a smaller set now, because the popback has already been done. Then I have to try to target sum minus an, otherwise I have to target sum. Any one of them works, I can make, there exists a subset with the correct sum. But if I want to keep track of what's happening, that will lead to some more code. But this will return the correct value, I think. If I want to keep track of which ones I have included, then I'll say add now a mutable vector of ints saying which have been included as the last argument. And of course, all recursive calls have to also pass in included. Not only that, now it can't look so nifty, because I have to separate out the two cases. So I have to say something like bool without equal to this, and then bool with equal to that, and I have to return with or without. But before that, I have to record in include what I have included. So I have to say something like if with, then int dot pushback n before you return. Now it's possible that both of them end up true. You can make the sum with and without, maybe. If it's a true set, then maybe not. But it depends whether there can be negative elements or not. But what you say if with is true, then I'll say that I included the element n. That is definitely correct. There's no problem with that. So I'd like you to trace what happened from only the white stuff to then include the yellow separately, so as to not get too confused. So if you drop the yellow stuff, then it should be clear that what I'm saying is, is there a subset which adds up to a? Well, yes, under two conditions. One is that a n is in s, and the remaining elements can, there is some subset which adds up to a minus a n. Or a n is not in s. And therefore, I can look for that and sum up to a. If either of these return true, then the answer to this is true. With or without. So let's code this up recursively and see what happens. I'll just read it in from scene. Let me read the set from, and then the sum target from the command line. Your things to enter. So I'll say something like, let's do one thing. I just wanted to check one. Just to see if popback works directly. Oh, set.popback returns a vector itself. Okay, never mind. So now, inside exists a subset, I'll implement that recursive call. Which is if size set.size equal to 0, and return target. Yeah. That is like see out, except that it doesn't wait for a new line to flush output to the screen. If you don't like it, I'll just replace it by see out. And put a new line, otherwise it doesn't show something. So subset sum, I'm supposed to pass the entries, the set. So let's say I have, I don't know, two, three, seven, 11. So can a subset of say five be achieved? Yes. Can a subset of eight be achieved? No. So now let's put the tracing code to see what is included and what is not. So suppose I have the inclusions there, and what I'll do is bool without equals, let's say if I do with here, I'll just make up a empty inclusion set. I'll call that. And then finally I have to do my printing. Let's see what I have handy. Printing big kind of stuff. That is not GCD, maybe quick sort, perhaps, to find my eternal print class. We should really make it a header. And of course, if the thing cannot be achieved, then nothing is printed. If you can achieve the sum, which is five, it's two and three. Which one's to add up? So this thing starts becoming fun if you add a bunch of things. Now there is a generalization of this where you can use each element multiple times. And a common use of that is making change. So I have to make up an amount out of one rupee, two rupees, five rupees, ten rupees and so on. Can you do it or can you not do it? Of course, if you have one rupee, you can do anything in infinite number. But in other cases, you may not be able to make exact change for an amount. So that's a natural application of this kind of trick. So try to extend this code to deal with changemaking.