<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Dynamic Programming - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Dynamic Programming - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 30 May 2026 08:55:55 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/dynamic-programming/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Learn Dynamic Programming Through Dynamic Visuals ]]>
                </title>
                <description>
                    <![CDATA[ Dynamic programming (DP) is often considered one of the most intimidating topics in coding interviews. It has a reputation for being abstract and counterintuitive, but it doesn't have to be. We just published a comprehensive Dynamic Programming cours... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-dynamic-programming-through-dynamic-visuals/</link>
                <guid isPermaLink="false">69711a5a740ddc945562fb4d</guid>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 21 Jan 2026 18:26:34 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769019975864/3c8b83cc-8602-4c4c-9476-6c8c1db3227d.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Dynamic programming (DP) is often considered one of the most intimidating topics in coding interviews. It has a reputation for being abstract and counterintuitive, but it doesn't have to be.</p>
<p>We just published a comprehensive Dynamic Programming course on the <a target="_blank" href="http://freeCodeCamp.org">freeCodeCamp.org</a> YouTube channel that uses a visual-first approach to learn these complex algorithms.</p>
<p>Created by Sheldon, an ex-Google engineer with over 10 years of experience, this course focuses on helping you develop a visual intuition for optimization. Instead of asking you to memorize hundreds of individual problems, Sheldon teaches you to recognize the underlying patterns that connect them.</p>
<p>The course breaks down dynamic programming into six fundamental patterns, explaining the logic and code (using Python) for each:</p>
<ol>
<li><p><strong>Constant Transition:</strong> Learn the basics with problems like the Climbing Stairs and House Robber, where the state depends on a fixed number of previous states.</p>
</li>
<li><p><strong>Grid Pattern:</strong> Explore 2D dynamic programming with problems like Unique Paths, learning how to build tables to solve navigation challenges.</p>
</li>
<li><p><strong>Two Sequences:</strong> Discover how to compare strings and sequences using 2D tables, covering classics like Longest Common Subsequence and Edit Distance.</p>
</li>
<li><p><strong>Interval DP:</strong> Tackle problems involving finding optimal substructures within intervals, such as the Longest Palindromic Subsequence.</p>
</li>
<li><p><strong>Non-Constant Transition:</strong> Understand complex transitions where a state depends on a variable number of previous states, illustrated by the Longest Increasing Subsequence problem.</p>
</li>
<li><p><strong>Knapsack-Like Problems:</strong> Master problems involving building specific sums or filling capacities, such as Partition Equal Subset Sum and Coin Change.</p>
</li>
</ol>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/66hDgWottdA">the freeCodeCamp.org YouTube channel</a> (2-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/66hDgWottdA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Dynamic Programming to Solve the 0/1 Knapsack Problem ]]>
                </title>
                <description>
                    <![CDATA[ The art of computer science often revolves around solving problems that are seemingly simple at first glance, but dig a little deeper and you'll find intricate challenges that demand creativity, logic, and precision. One such iconic problem is the 0/... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-dynamic-programming-to-solve-the-0-1-knapsack-problem/</link>
                <guid isPermaLink="false">66b2035e08bc664c3c097ea8</guid>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Mon, 25 Sep 2023 16:23:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/knapsack.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The art of computer science often revolves around solving problems that are seemingly simple at first glance, but dig a little deeper and you'll find intricate challenges that demand creativity, logic, and precision. One such iconic problem is the <strong>0/1 Knapsack Problem</strong>.</p>
<p>We just published a new course on the freeCodeCamp.org YouTube channel that offers a deep dive into the world of the 0/1 Knapsack Problem. You will learn how it works and discover how to build an efficient solution from scratch using C#. Gavin Lon developed this course.</p>
<p>The Knapsack Problem is often used as a pedagogical tool to teach two important paradigms in algorithm design: <strong>Dynamic Programming</strong> and <strong>Greedy Algorithms</strong>.</p>
<p>And if you're an aspiring programmer participating in job interviews, it could be a game-changer. Algorithmic interviews often touch upon optimization problems, and the strategies you'll learn here can be applied far beyond the knapsack.</p>
<h4 id="heading-course-breakdown"><strong>Course Breakdown</strong></h4>
<ol>
<li><strong>Introduction</strong>: Set the stage with a brief overview of what to expect throughout the course. Get a taste of the problem's historical significance and its place in the grand tapestry of computer science.</li>
<li><strong>Overview of the 0/1 Knapsack Problem</strong>: Dive into the heart of the matter. What exactly is this problem? Why is it termed "0/1"? Gavin demystifies the challenge, outlining the problem statement, its constraints, and real-world applications.</li>
<li><strong>Code the Algorithm Using C#</strong>: Transition from theory to practice. Follow Gavin as he demonstrates how to translate the problem into code, using the robust and versatile C# language.</li>
<li><strong>Dynamic Programming &amp; Memoization Strategy</strong>: Here's where the magic happens. Learn about the power of Dynamic Programming, a technique to simplify complex problems by breaking them down into smaller, more manageable subproblems. Get introduced to the concept of memoization, a strategy to store and reuse previously computed results, ensuring the algorithm runs in optimal time.</li>
<li><strong>Outputting the Items for the Knapsack in C#</strong>: It's not just about finding the maximum value—it's also about identifying which items to pack. In this section, Gavin will guide you through the process of extracting the actual items to include in the knapsack, making your solution complete.</li>
</ol>
<p>The course is available right now, for free, on the <a target="_blank" href="https://www.youtube.com/freecodecamp">freeCodeCamp.org YouTube channel</a> (1-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/hagBB17_hvg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Dynamic Programming Techniques in Java ]]>
                </title>
                <description>
                    <![CDATA[ Dynamic programming is a powerful technique that has been a cornerstone in the world of algorithms and computer science. It's a method that breaks down problems into smaller, more manageable sub-problems, solving each one only once and storing their ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-dynamic-programming-in-java/</link>
                <guid isPermaLink="false">66b20441903dc07a1351666b</guid>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 14 Sep 2023 02:01:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/dynamic.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Dynamic programming is a powerful technique that has been a cornerstone in the world of algorithms and computer science. It's a method that breaks down problems into smaller, more manageable sub-problems, solving each one only once and storing their solutions in case they're needed again. This approach is particularly useful for optimization problems, where you seek the best solution amongst a set of feasible solutions.</p>
<p>We just posted a course on the freeCodeCamp.org YouTube channel that will teach you Dynamic Programming techniques with Java.</p>
<p>Alvin Zablan created this course. It provides a deep dive into dynamic programming and teaches a lot of key algorithms.</p>
<h3 id="heading-what-is-dynamic-programming"><strong>What is Dynamic Programming?</strong></h3>
<p>Dynamic programming is a method for solving complex problems by breaking them down into simpler sub-problems. It is a way to solve problems by using solutions to smaller instances of the same problem.</p>
<p>The key idea behind dynamic programming is quite simple. In general, to solve a problem, you solve some sub-problems. Dynamic programming is used when the sub-problems are not independent, i.e., when sub-problems share sub-sub-problems. In this context, divide and conquer algorithms do more work than necessary, repeatedly solving the common sub-sub-problems. Dynamic programming algorithms remember past results and use them to find new results.</p>
<h3 id="heading-when-is-dynamic-programming-used"><strong>When is Dynamic Programming Used?</strong></h3>
<p>Dynamic programming is often used in optimization problems where we have to find the best solution among a set of feasible solutions. It's particularly useful when a problem has overlapping sub-problems. Instead of computing solutions to these sub-problems repeatedly, dynamic programming suggests solving each of these sub-problems just once, saving their solutions, and returning the saved solution when the same sub-problem is encountered again.</p>
<h3 id="heading-dynamic-programming-in-coding-interviews"><strong>Dynamic Programming in Coding Interviews</strong></h3>
<p>Dynamic programming is a favorite topic in coding interviews. Interviewers love to test the understanding, analytical skills, and problem-solving abilities of candidates using dynamic programming problems. It's not just about knowing the technique but also about understanding when and how to use it. Mastering dynamic programming can give you a significant edge in coding interviews.</p>
<h3 id="heading-course-breakdown"><strong>Course Breakdown</strong></h3>
<p>Here are the sections covered in the course:</p>
<ol>
<li><strong>fib</strong>: Dive into the Fibonacci sequence, a classic example to kickstart your dynamic programming journey.</li>
<li><strong>tribonacci</strong>: Explore the tribonacci sequence, a variation of the Fibonacci sequence.</li>
<li><strong>sum possible</strong>: Learn to determine if a sum is possible with given numbers.</li>
<li><strong>min change</strong>: Find out the minimum change required from a set of denominations.</li>
<li><strong>count paths</strong>: Count the number of paths in a grid.</li>
<li><strong>max path sum</strong>: Calculate the maximum path sum in a grid.</li>
<li><strong>non adjacent sum</strong>: Find the maximum sum without adding adjacent numbers.</li>
<li><strong>summing squares</strong>: Understand the concept of summing squares in dynamic programming.</li>
<li><strong>counting change</strong>: Learn different ways to count change using given denominations.</li>
</ol>
<p>Whether you're a beginner looking to understand the basics of dynamic programming or an advanced coder aiming to brush up your skills, this course has something for everyone. </p>
<p>You can watch the full course on <a target="_blank" href="https://www.youtube.com/watch?v=oFkDldu3C_4">the freeCodeCamp.org YouTube channel</a> (3-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/oFkDldu3C_4" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Dynamic Programming for Beginners – How to Solve Coding Challenges with Memoization and Tabulation ]]>
                </title>
                <description>
                    <![CDATA[ Dynamic Programming is style of coding where you store the results of your algorithm in a data structure while it runs. Understanding Dynamic Programming can help you solve complex programming problems faster. These methods can help you ace programmi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-dynamic-programing-to-solve-coding-challenges/</link>
                <guid isPermaLink="false">66b2043f712508eb1606787a</guid>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 03 Dec 2020 15:57:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/12/dynamicprogramming.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Dynamic Programming is style of coding where you store the results of your algorithm in a data structure while it runs.</p>
<p>Understanding Dynamic Programming can help you solve complex programming problems faster.</p>
<p>These methods can help you ace programming interview questions about data structures and algorithms. And they can improve your day-to-day coding as well.</p>
<p>We released a 5-hour course on Dynamic Programming on the freeCodeCamp.org YouTube channel.</p>
<p>Alvin Zablan developed this course. Alvin is an experienced programming instructor at Coderbyte, a popular website for technical interview prep and coding challenges.</p>
<p>In this course you will learn to use Dynamic Programming strategies to solve programming challenges such as:</p>
<ul>
<li>Calculating the 40th number of the Fibonacci sequence.</li>
<li>Counting the number of different ways to move through a 6x9 grid.</li>
<li>Given a set of coins, how can you make 27 cents in the least number of coins.</li>
</ul>
<p>This course uses images and animations to help you visualize problems and important concepts. After understanding problems conceptually, you will learn how to solve them in JavaScript using Dynamic Programming.</p>
<p>Even though this course uses JavaScript, you will learn concepts and knowledge that you can apply to other programming languages, including Python.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-27.png" alt="Image" width="600" height="400" loading="lazy">
<em>Dynamic Programming can really speed up your work. But common sense can speed things up even further. (Traveling Salesman problem webcomic by <a target="_blank" href="https://xkcd.com/399/">XKCD</a>)</em></p>
<h2 id="heading-dynamic-programming-methods-this-course-covers">Dynamic Programming Methods This Course Covers</h2>
<p>Part one of this course focuses on Memoization methods. This is where you use recursion and store the intermediate results of your algorithm. You can then access those results on later trips through your your loops.</p>
<p>Here are the Memoization strategies this course covers:</p>
<ul>
<li>fib memoization</li>
<li>gridTraveler memoization</li>
<li>memoization recipe</li>
<li>canSum memoization</li>
<li>howSum memoization</li>
<li>bestSum memoization</li>
<li>canConstruct memoization</li>
<li>countConstruct memoization</li>
<li>allConstruct memoization</li>
</ul>
<p>And part two focuses on Tabulation strategies. These involve building up a table of data iteratively.</p>
<p>Here are the Tabulation strategies this course covers:</p>
<ul>
<li>fib tabulation</li>
<li>gridTraveler tabulation</li>
<li>tabulation recipe</li>
<li>canSum tabulation</li>
<li>howSum tabulation</li>
<li>bestSum tabulation</li>
<li>canConstruct tabulation</li>
<li>countConstruct tabulation</li>
<li>allConstruct tabulation</li>
</ul>
<p>You can watch the full course on <a target="_blank" href="https://www.youtube.com/watch?v=oBt53YbR9Kk">the freeCodeCamp.org YouTube channel</a> (5-hour watch).</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Dynamic Programming Made Easy ]]>
                </title>
                <description>
                    <![CDATA[ By Ashwin Sharma P Dynamic Programming is an approach where the main problem is divided into smaller sub-problems, but these sub-problems are not solved independently. For a problem to be solved using dynamic programming, the sub-problems must be ove... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/dynamic-programming-made-easy/</link>
                <guid isPermaLink="false">66d45d97706b9fb1c166b91a</guid>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 15 Sep 2020 19:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/thisisengineering-raeng-uOhBxB23Wao-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ashwin Sharma P</p>
<p>Dynamic Programming is an approach where the main problem is divided into smaller sub-problems, but these sub-problems are not solved independently.</p>
<p>For a problem to be solved using dynamic programming, the sub-problems must be overlapping. This means that two or more sub-problems will evaluate to give the same result.</p>
<p>So, we use the memoization technique to recall the result of the already solved sub-problems for future use. We then use cache storage to store this result, which is used when a similar sub-problem is encountered in the future.</p>
<p>Now let's look at this topic in more depth.</p>
<h2 id="heading-what-is-memoization">What is memoization?</h2>
<p>Memoization is the technique of memorizing the results of certain specific states, which can then be accessed to solve similar sub-problems. In other words, it is a specific form of caching.</p>
<p>This ensures that the results already computed are stored generally as a hashmap. This decreases the run time significantly, and also leads to less complicated code.</p>
<p>But we know that any benefit comes at the cost of something. So, when we use dynamic programming, the time complexity decreases while space complexity increases.</p>
<h2 id="heading-different-approaches-in-dp">Different approaches in DP</h2>
<p>In dynamic programming, we can either use a top-down approach or a bottom-up approach.</p>
<p>The top-down approach involves solving the problem in a straightforward manner and checking if we have already calculated the solution to the sub-problem. </p>
<p>This approach includes recursive calls <em>(repeated calls of the same function)</em>. It builds up a call stack, which leads to memory costs. It is also vulnerable to stack overflow errors.</p>
<p>The bottom-up approach includes first looking at the smaller sub-problems, and then solving the larger sub-problems using the solution to the smaller problems.</p>
<p> This approach avoids memory costs that result from recursion.</p>
<p>But both the top-down approach and bottom-up approach in dynamic programming have the same time and space complexity. So in the end, using either of these approaches does not make much difference.</p>
<p>Just a quick note: dynamic programming is not an algorithm. But I have seen some people confuse it as an algorithm (including myself at the beginning). </p>
<p>It is used only when we have an overlapping sub-problem or when extensive recursion calls are required. It is a way to improve the performance of existing slow algorithms.</p>
<p>This means, also, that the time and space complexity of dynamic programming varies according to the problem.</p>
<h2 id="heading-dynamic-programming-example">Dynamic Programming Example</h2>
<p>Now let us solve a problem to get a better understanding of how dynamic programming actually works.</p>
<p>Consider the problem of finding the longest common sub-sequence from the given two sequences.</p>
<p>⇒ <em>‘gtcab’</em> and <em>‘gxtxab’</em></p>
<p>We can solve this problem using a naive approach, by generating all the sub-sequences for both and then find the longest common sub-sequence from them. </p>
<p>But the time complexity of this solution grows exponentially as the length of the input continues increasing.</p>
<p><strong>So, how do we know that this problem can be solved using dynamic programming?</strong>‌‌‌‌</p>
<p>For the two strings we have taken, we use the below process to calculate the longest common sub-sequence (LCS).</p>
<p>As we can see, here we divide the main problem into smaller sub-problems. Let us check if any sub-problem is being repeated here.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/freecodecamp_first_article--2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Dividing the main problem into sub-problems</em></p>
<p>‌‌We can see here that two sub-problems are overlapping when we divide the problem at two levels. </p>
<p>If we further go on dividing the tree, we can see many more sub-problems that overlap. So we conclude that this can be solved using dynamic programming.</p>
<p>Next, let us look at the general approach through which we can find the longest common sub-sequence (LCS) using dynamic programming.</p>
<h2 id="heading-how-to-fill-the-matrix">How to fill the matrix?</h2>
<p>We will use the matrix method to understand the logic of solving the longest common sub-sequence using dynamic programming. </p>
<p>Here we will only discuss how to solve this problem – that is, the algorithm part. And for that we use the matrix method.</p>
<p>Look at the below matrix. We have filled the first row with the first sequence and the first column with the second sequence. </p>
<p>Then we populated the second row and the second column with zeros for the algorithm to start. We denote the rows with <strong>‘i’</strong> and columns with <strong>‘j’</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/freecodecamp_first_article2.png" alt="Matrix entry" width="600" height="400" loading="lazy">
<em>Matrix entry</em></p>
<p>Now we move on to fill the cells of the matrix. Compare the two sequences until the particular cell where we are about to make the entry.</p>
<p>The length/count of common sub-sequences remains the same until the last character of both the sequences undergoing comparison becomes the same.</p>
<p>If the sequences we are comparing do not have their last character equal, then the entry will be the maximum of the entry in the column left of it and the entry of the row above it. </p>
<p>When the last characters of both sequences are equal, the entry is filled by incrementing the upper left diagonal entry of that particular cell by <strong>1</strong>.</p>
<p><strong>The logic we use here to fill the matrix is given below:‌</strong></p>
<pre><code><span class="hljs-keyword">if</span>(input[i]==input[j])              <span class="hljs-comment">//Check if last characters are equal</span>
T[i][j]=T[i<span class="hljs-number">-1</span>][j<span class="hljs-number">-1</span>]+<span class="hljs-number">1</span>               <span class="hljs-comment">//Entry is incremental of upper left element</span>
<span class="hljs-keyword">else</span>                                <span class="hljs-comment">//If the last character are not equal</span>
T[i][j]=max(T[i<span class="hljs-number">-1</span>][j], T[i][j<span class="hljs-number">-1</span>])   <span class="hljs-comment">//Entry is max of element to its left and top</span>
</code></pre><p>The bottom right entry of the whole matrix gives us the length of the longest common sub-sequence.</p>
<h2 id="heading-finding-the-longest-common-sub-sequence">Finding the longest common sub-sequence</h2>
<p>In order to get the longest common sub-sequence, we have to traverse from the bottom right corner of the matrix. Then we check from where the particular entry is coming. </p>
<p>That is, we can check <em>whether it is the maximum of its left and top entry</em> or else is it the <em>incremental entry of the upper left diagonal element?</em></p>
<p>We repeat this process until we reach the top left corner of the matrix. The sub-sequence we get by combining the path we traverse <em>(only consider those characters where the arrow moves diagonally)</em> will be in the reverse order. </p>
<p>We have to reverse this obtained sequence to get the correct longest common sub-sequence. So in this particular example, the longest common sub-sequence is <strong>‘gtab’</strong>.</p>
<p>I have made a detailed video on how we fill the matrix so that you can get a better understanding. You can find it here: <a target="_blank" href="https://youtu.be/hVx1X46iLVk"><strong>Video Explanation</strong></a><strong>.</strong></p>
<h2 id="heading-what-did-we-learn">What did we learn?</h2>
<p>In this article, we learned what dynamic programming is and how to identify if a problem can be solved using dynamic programming. </p>
<p>Then we went on to study the complexity of a dynamic programming problem. </p>
<p>Next we learned how we can solve the longest common sub-sequence problem using dynamic programming.</p>
<p>I hope you enjoyed it and learned something useful from this article.</p>
<p>If you found this post helpful, please share it. If you have any feedback, feel free to contact me on <a target="_blank" href="https://twitter.com/ashwinsharmap">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A variation on the Knapsack Problem: how to solve the Partition Equal Subset Sum problem in Java ]]>
                </title>
                <description>
                    <![CDATA[ By Fabian Terh Previously, I wrote about solving the Knapsack Problem (KP) with dynamic programming. You can read about it here. Today I want to discuss a variation of KP: the partition equal subset sum problem. I first saw this problem on Leetcode —... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-variation-on-the-knapsack-problem-how-to-solve-the-partition-equal-subset-sum-problem-in-java-7e0fc047f19b/</link>
                <guid isPermaLink="false">66c34368790a62b5fbf7b867</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 10 May 2019 16:53:32 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*u-j8qYS9582smJPe1ZzNcw.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Fabian Terh</p>
<p>Previously, I wrote about solving the Knapsack Problem (KP) with dynamic programming. <a target="_blank" href="https://medium.freecodecamp.org/how-to-solve-the-knapsack-problem-with-dynamic-programming-eb88c706d3cf">You can read about it here</a>.</p>
<p>Today I want to discuss a variation of KP: the <a target="_blank" href="https://leetcode.com/problems/partition-equal-subset-sum/">partition equal subset sum problem</a>. I first saw this problem on Leetcode — this was what prompted me to learn about, and write about, KP.</p>
<p>This is the problem statement (reproduced partially without examples):</p>
<blockquote>
<p>Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.</p>
</blockquote>
<p>For the full problem statement, with constraints and examples, check out the <a target="_blank" href="https://leetcode.com/problems/partition-equal-subset-sum/">Leetcode problem</a>.</p>
<h3 id="heading-dynamic-programming">Dynamic programming</h3>
<p>Like with KP, we’ll be solving this using dynamic programming. Since this is a variation of KP, the logic and methodology is largely similar.</p>
<h3 id="heading-solution">Solution</h3>
<p>We will house our solution in a method that returns a boolean — true if the array can be partitioned into equal subsets, and false otherwise.</p>
<h4 id="heading-step-1-guarding-against-odd-array-sum">Step 1: Guarding against odd array sum</h4>
<p>Trivially, if all the numbers in the array add up to an odd sum, we can return false. We only proceed if the array adds up to an even sum.</p>
<h4 id="heading-step-2-creating-the-table">Step 2: Creating the table</h4>
<p>Next, we create the table.</p>
<p>Table rows represent the set of array elements to be considered, while table columns indicate the sum we want to arrive at. Table values are simply boolean values, indicating whether a sum (column) can be arrived at with a set of array elements (row).</p>
<p>Concretely, row <em>i</em> represents a set of array elements from indices 0 to (<em>i</em>-1). The reason for this offset of 1 is because row 0 represents an empty set of elements. Therefore, row 1 represents the first array element (index 0), row 2 represents the first two array elements (indices 0–1), and so on. In total, we create <code>n + 1</code> rows, inclusive of 0.</p>
<p>We only want to know if we can sum up exactly to half the total sum of the array. So we only need to create <code>totalSum / 2 + 1</code> columns, inclusive of 0.</p>
<h4 id="heading-step-3-pre-filling-the-table">Step 3: Pre-filling the table</h4>
<p>We can immediately begin filling the entries for the base cases in our table — row 0 and column 0.</p>
<p>In the first row, every entry — except the first — must be <code>false</code>. Recall that the first row represents an empty set . Naturally, we are unable to arrive at any target sum — column number — except 0.</p>
<p>In the first column, every entry must be <code>true</code>. We can always,trivially, arrive at a target sum of 0, regardless of the set of elements we have to work with.</p>
<h4 id="heading-step-4-building-the-table-the-crux-of-the-problem">Step 4: Building the table (the crux of the problem)</h4>
<p>Some entry in the table at row <em>i</em> and column <em>j</em> is <code>true</code> (attainable) if one of the following three conditions are satisfied:</p>
<ol>
<li>the entry at row <em>i</em>-1 and column <em>j</em> is <code>true</code>. Recall what the row number represents. Therefore, if we are able to attain a particular sum with a subset of the elements that we have presently, we can also attain that sum with our current set of elements — by simply not using the extra elements. This is trivial. Let’s call this <code>prevRowIsTrue</code>.</li>
<li>The current element is exactly the sum we want to attain. This is also trivially true. Let’s call this <code>isExactMatch</code>.</li>
<li>If the above two conditions are not satisfied, we have one remaining way of attaining our target sum. Here, we use the current element — the additional element in the set of elements in our current row compared to the set of elements in the previous row — and check that we are able to attain the remainder of the target sum. Let’s call this <code>canArriveAtSum</code>.</li>
</ol>
<p>Let’s unpack condition 3. We can only use the current element <strong>if</strong> it is less than our target sum. If they’re equal, condition 2 would be satisfied. If it’s larger, we can’t use it. Therefore, the first step is to ensure that current element &lt; target sum.</p>
<p>After using our current element, we are left with the remainder of our target sum. We then check if that is attainable by checking the corresponding entry in the row above.</p>
<p>As with regular KP, we want to progressively build our table from the bottom-up. We start with the base cases, until we arrive at our final solution.</p>
<h4 id="heading-step-5-returning-the-answer">Step 5: Returning the answer</h4>
<p>We simply return <code>return mat[nums.length][totalSum / 2]</code>.</p>
<h3 id="heading-working-code">Working code</h3>
<p>Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An intro to Algorithms: Dynamic Programming ]]>
                </title>
                <description>
                    <![CDATA[ By Meet Zaveri 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... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/an-intro-to-algorithms-dynamic-programming-dd00873362bb/</link>
                <guid isPermaLink="false">66c343f093db2451bd4413fb</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 30 Apr 2019 15:33:33 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*aExd095nIEBdoJ_ANTVCbw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Meet Zaveri</p>
<p>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 <strong>same output</strong> when you had supplied the <strong>same input</strong>. So it’s like you are doing re-computation of a result that was previously achieved by specific input for its respective output.</p>
<p>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).</p>
<blockquote>
<p>Those who cannot remember the past are condemned to repeat it. ~Dynamic Programming</p>
</blockquote>
<p>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.</p>
<h3 id="heading-diving-into-dynamic-programming">Diving into dynamic programming</h3>
<p>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.</p>
<p>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.</p>
<p>For instance, the <a target="_blank" href="http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fib.html">Fibonacci numbers</a> <code>0,1,1,2,3,5,8,13,…</code> have a simple description where each term is related to the two terms before it. If <code>F(n)</code> is the <code>n</code>th term of this series then we have <code>F(n) = F(n-1) + F(n-2)</code>. This is called a <strong>recursive formula</strong> or a <strong>recurrence relation.</strong> It needs earlier terms to have been computed in order to compute a later term.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/2MrMcNofQOnzWkh-hkALV4udgyak1WqE7D1w" alt="Image" width="800" height="600" loading="lazy"></p>
<p>The majority of Dynamic Programming problems can be categorized into two types:</p>
<ol>
<li><strong>Optimization problems.</strong></li>
<li><strong>Combinatorial problems.</strong></li>
</ol>
<p>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.</p>
<h3 id="heading-an-approach-to-solve-top-down-vs-bottom-up">An approach to solve: top-down vs bottom-up</h3>
<p>There are the following two main different ways to solve the problem:</p>
<p><strong>Top-down:</strong> 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 <strong><em>Memoization.</em></strong></p>
<p><strong>Bottom-up:</strong> 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 <strong><em>Tabulation</em></strong> (<strong>table-filling algorithm</strong>).</p>
<p>In reference to iteration vs recursion, bottom-up uses iteration and the top-down uses recursion.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/bcZt7dF4Z8GUcRAicU7eETW98YOikSzsJqKa" alt="Image" width="800" height="1066" loading="lazy">
<em>The visualization displayed in the image is not correct acc. to theoretical knowledge, but I have displayed in an understandable manner</em></p>
<p>Here there is a comparison between a naive approach vs a DP approach. You can see the difference by the time complexity of both.</p>
<h3 id="heading-memoization-dont-forget">Memoization: Don’t forget</h3>
<p><a target="_blank" href="http://jeffe.cs.illinois.edu/">Jeff Erickson</a> describes in his notes, for Fibonacci numbers:</p>
<blockquote>
<p>The obvious reason for the recursive algorithm’s lack of speed is that it computes the same Fibonacci numbers over and over and over.</p>
</blockquote>
<p><img src="https://cdn-media-1.freecodecamp.org/images/y9J0-FSzmI3RgyCX1FOkgFOfoy0gnKZtTObP" alt="Image" width="472" height="180" loading="lazy">
_From Jeff Erickson’s notes CC: [http://jeffe.cs.illinois.edu/](http://jeffe.cs.illinois.edu/" rel="noopener" target="<em>blank" title=")</em></p>
<p>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.</p>
<p><strong>Memoization</strong> refers to the technique of caching and reusing previously computed results.</p>
<p>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 <strong>mapping</strong> of key and value). You do it “<strong>top-down</strong>” in the sense that you solve the “top” problem first (which typically recurses down to solve the sub-problems).</p>
<p><strong>Pseudocode for memoization</strong>:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Zc2XojBYGYnFvIdKnjs-vh5uy-TETK5h2guX" alt="Image" width="800" height="388" loading="lazy"></p>
<p>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.</p>
<p>Remember that there is a tradeoff of extra overhead with respect to the tabulation method.</p>
<p>However, if you want more visualizations for memoization, then I suggest looking into <a target="_blank" href="https://www.youtube.com/watch?v=Taa9JDeakyU">this video</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/pw42NcPn9a9mVCLeKSQI-y75vTGTcQifI8Pt" alt="Image" width="800" height="455" loading="lazy">
<em>In a top-down manner.</em></p>
<h3 id="heading-tabulation-filling-up-in-tabular-form">Tabulation: Filling up in tabular form</h3>
<p>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’.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/N61EAtUcJ04sfTINdBEzulljU56WqnSGPelV" alt="Image" width="323" height="155" loading="lazy">
_From Jeff Erickson’s notes CC: [http://jeffe.cs.illinois.edu/](http://jeffe.cs.illinois.edu/" rel="noopener" target="<em>blank" title=")</em></p>
<p>Tabulation does it in <strong>“bottom-up”</strong> 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.</p>
<p><strong>Pseudocode for tabulation:</strong></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/sluFNyPCslPYri9s1Jip7-xyYdvKJcOWlnhJ" alt="Image" width="800" height="512" loading="lazy">
<em>Pseudocode with Fibonacci tree</em></p>
<p>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.</p>
<h3 id="heading-looking-back-in-history">Looking back in history</h3>
<p>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.</p>
<p>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.</p>
<h4 id="heading-wrapping-up">Wrapping up</h4>
<p>That’s it. This is part 2 of the algorithm series I started last year. In my <a target="_blank" href="https://codeburst.io/algorithms-i-searching-and-sorting-algorithms-56497dbaef20">previous post</a>, 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.</p>
<p>Hope you liked it and I’ll be soon looking to add a third one in the series soon. Happy coding!</p>
<p>Resources:</p>
<p><a target="_blank" href="https://www.hackerearth.com/practice/algorithms/dynamic-programming"><strong>Introduction to Dynamic Programming 1 Tutorials &amp; Notes | Algorithms | HackerEarth</strong></a><br><a target="_blank" href="https://www.hackerearth.com/practice/algorithms/dynamic-programming">_The image above says a lot about Dynamic Programming. So, is repeating the things for which you already have the…_www.hackerearth.com</a><a target="_blank" href="https://www.topcoder.com/community/competitive-programming/tutorials/dynamic-programming-from-novice-to-advanced/"><strong>Community — Competitive Programming — Competitive Programming Tutorials — Dynamic Programming: From…</strong></a><br><a target="_blank" href="https://www.topcoder.com/community/competitive-programming/tutorials/dynamic-programming-from-novice-to-advanced/">_Community — Competitive Programming — Competitive Programming Tutorials — Dynamic Programming: From Novice to Advanced_www.topcoder.com</a></p>
<p><a target="_blank" href="https://www.geeksforgeeks.org/overlapping-subproblems-property-in-dynamic-programming-dp-1/">https://www.geeksforgeeks.org/overlapping-subproblems-property-in-dynamic-programming-dp-1/</a></p>
<p>Special props to Jeff Erickson and his notes for algorithm — <a target="_blank" href="http://jeffe.cs.illinois.edu/">http://jeffe.cs.illinois.edu/</a></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/3MSAzv4xVUKSIIQEkTfiAK2lq8mzGKmmOBzB" alt="Image" width="800" height="436" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Change the signs: how to use dynamic programming to solve a competitive programming question ]]>
                </title>
                <description>
                    <![CDATA[ By Sachin Malhotra If you’re a competitive programmer like I am, one of the best feelings in the world is seeing your program getting accepted on first try on one of the most famous programming platforms, CodeChef. I was an avid competitive programme... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/just-change-the-signs-how-to-solve-a-competitive-programming-question-f9730e8f04a9/</link>
                <guid isPermaLink="false">66c3595df83dfae169b2c001</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Competitive programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Problem Solving ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 01 Jun 2018 22:00:05 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*kdC2W2WKEjPIG1pRCk0qmg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sachin Malhotra</p>
<p>If you’re a competitive programmer like I am, one of the best feelings in the world is seeing your program getting accepted on first try on one of the most famous programming platforms, <a target="_blank" href="https://www.codechef.com/">CodeChef</a>.</p>
<p>I was an avid competitive programmer during undergrad, and then lost touch with it when working as a developer @Hike. However, I recently started out into this adventurous world of programming again, all thanks to my friend <a target="_blank" href="https://www.freecodecamp.org/news/just-change-the-signs-how-to-solve-a-competitive-programming-question-f9730e8f04a9/undefined">Divya Godayal</a>.</p>
<p>The <a target="_blank" href="https://www.codechef.com/MAY18">CodeChef May 2018 Long Challenge</a> ended about an hour ago, and I decided to write this article as a post describing one of the questions in the competition.</p>
<p>Without wasting any more time, let’s get to it.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Y6UspCo7zHVxvZE-xRG3pERSJQy4CfD6EGU3" alt="Image" width="800" height="1091" loading="lazy"></p>
<h3 id="heading-unravelling-the-problem-statement">Unravelling the Problem Statement</h3>
<p>Let’s look at some examples to better understand what the problem statement is asking for.</p>
<p>Consider the following number sequence.</p>
<pre><code><span class="hljs-number">4</span> <span class="hljs-number">3</span> <span class="hljs-number">1</span> <span class="hljs-number">2</span>
</code></pre><p>Now the question asks us to perform a certain operation (possibly 0 times, leaving the sequence unchanged). We can negate a certain subsequence of numbers and get a new sequence.</p>
<pre><code><span class="hljs-number">-4</span> <span class="hljs-number">3</span> <span class="hljs-number">1</span> <span class="hljs-number">24</span> <span class="hljs-number">-3</span> <span class="hljs-number">1</span> <span class="hljs-number">-24</span> <span class="hljs-number">3</span> <span class="hljs-number">-1</span> <span class="hljs-number">24</span> <span class="hljs-number">3</span> <span class="hljs-number">1</span> <span class="hljs-number">-2</span><span class="hljs-number">-4</span> <span class="hljs-number">-3</span> <span class="hljs-number">1</span> <span class="hljs-number">2</span> etc.
</code></pre><p>The question says that the resulting sequence should satisfy the following constraint:</p>
<p><strong>The sum of elements of any substring with length greater than 1 is strictly positive.</strong></p>
<p>Clearly, the following sequences are not valid:</p>
<pre><code><span class="hljs-number">-4</span> <span class="hljs-number">3</span> <span class="hljs-number">1</span> <span class="hljs-number">24</span> <span class="hljs-number">-3</span> <span class="hljs-number">1</span> <span class="hljs-number">-2</span> <span class="hljs-number">4</span> <span class="hljs-number">3</span> <span class="hljs-number">1</span> <span class="hljs-number">-2</span> <span class="hljs-number">-4</span> <span class="hljs-number">-3</span> <span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">-4</span> <span class="hljs-number">-3</span> <span class="hljs-number">-1</span> <span class="hljs-number">-24</span> <span class="hljs-number">3</span> <span class="hljs-number">-1</span> <span class="hljs-number">-2</span>
</code></pre><p>We only have 2 valid subsequences that can be obtained by performing the operation mentioned above. <strong>Note:</strong> we haven’t written down all the possible subsequences. That would be 2^n, that is 16 in this case, because for every number we have two options. Either to negate it, or not.</p>
<p>So the two valid sequences are:</p>
<pre><code><span class="hljs-number">4</span> <span class="hljs-number">3</span> <span class="hljs-number">1</span> <span class="hljs-number">2</span>
</code></pre><p>and</p>
<pre><code><span class="hljs-number">4</span> <span class="hljs-number">3</span> <span class="hljs-number">-1</span> <span class="hljs-number">2</span>
</code></pre><p>The original sequence would always be one of the valid sequences as all the numbers in it are positive.</p>
<p>Now the question asks us to find the sequence with the minimum sum. So for the example we have considered, the sequence required would be <code>4 3 -1 2</code> .</p>
<h3 id="heading-would-greedy-work">Would Greedy Work?</h3>
<p>A greedy approach in this question would be that if it is possible to negate a number while satisfying the given constraints, then we should negate that number. This approach however, would not always give the right results. Consider the following example.</p>
<pre><code><span class="hljs-number">4</span> <span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">2</span>
</code></pre><p>Here, it is possible to have these three valid sets of numbers:</p>
<pre><code><span class="hljs-number">4</span> <span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">2</span>           <span class="hljs-number">4</span> <span class="hljs-number">-1</span> <span class="hljs-number">3</span> <span class="hljs-number">2</span>           <span class="hljs-number">4</span> <span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">-2</span>
</code></pre><p>Clearly, both the numbers 2 and 1 can be negated. But not both of them at the same time. If we negate a number greedily — that is, if a number can be negated, then we negate it — then it is possible that we might end up negating the number 1. Then you won’t be able to negate the number 2. This would give us a suboptimal solution.</p>
<p>So this Greedy approach would not work here. We have to <strong>“try out a specific choice of whether to negate or not for a number and see what choice gives us the optimal solution”<em>.</em></strong></p>
<p>This smells like Dynamic Programming.</p>
<h3 id="heading-good-ol-dynamic-programming">Good ol’ Dynamic Programming</h3>
<p>One of the most interesting algorithmic techniques out there, and possibly one of the most dreaded, is dynamic programming. This is the technique we are going to use to solve this particular problem.</p>
<p>Two of the most important steps in any dynamic programming problem are:</p>
<ol>
<li>Identifying the recurrent relation.</li>
<li>Figuring out what to <a target="_blank" href="https://www.interviewcake.com/concept/java/memoization"><strong>memoize</strong></a><strong>. (not memoRize :P)</strong></li>
</ol>
<p>The DP-based approach here is divided into two basic parts.</p>
<ul>
<li>One is the main recursion that we use to find out the <strong>minimum sum of the final set</strong>. Note, the dynamic programming is not directly used to obtain the final set, just the sum of the final set of numbers. So our dynamic programming approach would correctly find out the sum for the example given above as 8. <code>4 + 3 + (-1) + 2 = 8</code> .</li>
<li>What we actually need is the final modified set of numbers where some (possibly none) of the numbers are negated. We use the concept of a <strong>parent pointer</strong> and <strong>backtracking</strong> to find out the actual set of numbers.</li>
</ul>
<p>Let’s move onto our recursion relation for our dynamic programming approach.</p>
<p>Before describing the recursive relation an important observation to make here is that if a number has been negated, <strong>then any adjacent number to it can not be negative</strong>. That is, two adjacent numbers cannot be negative as that would give a substring of length 2 whose sum is negative, and that is not allowed according to the question.</p>
<p>For the recurrence relation, we need two variables. One is the index number of where we are in the array, and one is a boolean value that tells us if the previous number (one left to the previous number) is negated or not. So if the current index is <code>i</code>, then the boolean value would tell us if the number at <code>i — 2</code> was negated or not. You will know the importance of this boolean variable in the next paragraph.</p>
<p>We need to know in <code>O(1)</code> if a number <strong>can</strong> be negated or not. Since we are following a recursion with memoization-based solution, whenever we are at an index <code>i</code> in the recursion, we are sure that the numbers to the right (<code>i+ 1</code> onwards) have not been processed up to this point. This means that all of them are still positive.</p>
<p>The choice of whether the number at index <code>i</code> can be negated is dependent upon the right hand side (if there is one) and the left hand side (if there is one). The right hand side is easy. All we need to check is if</p>
<pre><code>number[i] &lt; number[i + <span class="hljs-number">1</span>]
</code></pre><p>because if this is not true, then adding these two would give a negative value for the substring <code>[i, i + 1]</code> thus making it an invalid operation.</p>
<p>Now comes the tricky part. We need to see if negating the number at <code>i</code> will cause a substring of negative sum to the left or not. When we reach the index <code>i</code> in our recursion, we have already processed the numbers before it, and some might have been negated as well.</p>
<p>So say we have this set of numbers <code>4 1 2 1</code> and we had negated the first <code>1</code> and we are now processing the last number ( <code>1</code> ).</p>
<pre><code><span class="hljs-number">4</span> <span class="hljs-number">-1</span> <span class="hljs-number">2</span> [<span class="hljs-number">1</span>]
</code></pre><p>The last number in square brackets is the one we are processing right now. As far as the right hand side is concerned, since there is none, we can negate it. We need to check if negating this 1 at index 3 (0 based indexing) would cause any substring to the left of ≤ 0 sum. As you can see, it will produce such a substring.</p>
<pre><code><span class="hljs-number">-1</span> <span class="hljs-number">2</span> <span class="hljs-number">-1</span>
</code></pre><p>This substring would have a 0 sum, and that is invalid according to the question. After negating a subsequence of numbers, the substrings in the final set should have a sum which is strictly positive. All the substrings of length &gt; 1.</p>
<p>We cannot apply the following approach here directly:</p>
<pre><code><span class="hljs-keyword">if</span> number[i] &lt; number[i - <span class="hljs-number">1</span>], then it is good to go on negation.
</code></pre><p>because, although <code>1 &lt;</code>; 2 , if we negate that last 1 as well we will have an invalid set of numbers as seen above. So this simple approach or check won’t work here.</p>
<p>Here comes the boolean variable which tells us if, given an index <code>i</code>, the number at <code>i — 2</code> was negated or not. Consider the two scenarios.</p>
<ul>
<li>Yes, the number at index <code>i — 2</code> was negated like in the example just showcased. In that case, negation of the number at <code>i — 2</code> would have a capacity reduction for number at <code>i — 1</code>. In the example <code>4 1 2 1</code> , negating the 1 at index 1(0 based indexing) would reduce the capacity of the number 2 (at index 2) by 1. We refer to remaining values of numbers as capacities here. We need to consider this reduced capacity when performing the check to see if a number can be negated or not.</li>
</ul>
<pre><code>number[i] &lt; reducedCapacityOfNumberAt(i - <span class="hljs-number">1</span>)
</code></pre><ul>
<li>In case the number at index <code>i — 2</code> wasn’t negated, the number at <code>i — 1</code> is at it’s full capacity. The simple check</li>
</ul>
<pre><code>number[i] &lt; number[i - <span class="hljs-number">1</span>]
</code></pre><p>would be enough to see if we can negate the number at index <code>i</code> .</p>
<p>Let’s look at the code for the recursion containing all the ideas discussed above.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/a4tshHUm1WyoHHO0hK-050EfDySLR3KHVwzY" alt="Image" width="800" height="648" loading="lazy"></p>
<p>That’s all nice and dandy. But, this is just recursion, and the heading says dynamic programming. That means there would be overlapping subproblems. Let us look at the recursion tree to see if there are any.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-6EItwtVtgzqUHrsbEJODoMoxV2woN6iN7Nv" alt="Image" width="800" height="687" loading="lazy"></p>
<p>As you can see, there are overlapping subproblems in the recursion tree. That is why we can use memoization.</p>
<p>The memoization is as simple as:</p>
<pre><code><span class="hljs-string">""</span><span class="hljs-string">" This comes at the top. We check if the state represented by the tuple of the index and the boolean variable is already cached "</span><span class="hljs-string">""</span>
</code></pre><pre><code><span class="hljs-keyword">if</span>(memo[i][is_prev_negated] != INF) {    <span class="hljs-keyword">return</span> memo[i][is_prev_negated];}
</code></pre><pre><code>...... CODE
</code></pre><pre><code># Cache the minimum sum <span class="hljs-keyword">from</span> <span class="hljs-built_in">this</span> index onwards.memo[i][is_prev_negated] = min(pos, neg);
</code></pre><pre><code># The parent pointer is used <span class="hljs-keyword">for</span> finding out the final set <span class="hljs-keyword">of</span> #sparent[i][is_prev_negated] = min(pos, neg) == pos ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>;
</code></pre><p>As pointed out earlier, this recursive approach would return the minimum sum of the set of numbers possible after making the valid set of modifications to them.</p>
<p>The question, however, asks us to actually print the final set of numbers that gives the minimum sum after making such modifications. For that, we need to use a parent pointer that would tell us at every index and boolean variable <code>is_prev_negated</code> ’s value as to what optimal action was taken.</p>
<pre><code>parent[i][is_prev_negated] = min(pos, neg) == pos ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>;
</code></pre><p>So we simply store 1 or -1 depending upon if negating the number at index i (if possible!) gave us the minimum sum or if choosing to ignore it gave the minimum sum.</p>
<h3 id="heading-backtracking">Backtracking</h3>
<p>Now comes the part where we backtrack to find the solution to our original problem. Note that the decision for the very first number is what propagates the recursion further. If the first number was negated, the second number would be positive and the third number’s decision can be found using <code>parent[2][true]</code>. Similarly, if the first number wasn’t negated, then we move onto the second number and it’s decision can be found using <code>parent[1][false]</code> and so on. Let’s look at the code.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-rimpa-Iqfb1y22u7qbQZgjxkU-A2ziBQZrW" alt="Image" width="800" height="591" loading="lazy"></p>
<h3 id="heading-a-better-approach">A Better Approach</h3>
<p>If you take a look at the space complexity of the solution suggested, you will see that it’s a 2 dimensional dynamic programming solution because the state of the recursion is represented by two variables i.e. the index <code>i</code> representing what number of the array we are considering and then the boolean variable <code>is_prev_negated</code> . So the space complexity and the time complexity would be O(n*2) which is essentially O(n).</p>
<p>However, there is a slightly better approach as well to solving this problem as suggested by <a target="_blank" href="https://www.freecodecamp.org/news/just-change-the-signs-how-to-solve-a-competitive-programming-question-f9730e8f04a9/undefined">Divya Godayal</a>. This problem can even be solved by 1 dimensional dynamic programming based solution.</p>
<p>Essentially, the boolean variable <code>is_prev_negated</code> is helping us to decide if we can negate a given number at index <code>i</code> or not as far as the left hand side of the array is concerned i.e. <code>all the numbers from 0 .. i-1</code> because the right hand side is anyways safe as all the numbers on that side are positive (as the recursion hasn’t reached them yet). So for the right hand side we simply checked the number at <code>i+1</code> but for the left hand side of index <code>i</code> we had to make use of the boolean variable <code>is_prev_negated</code> .</p>
<p>It turns out, that we can simply skip this boolean variable altogether and simply look ahead to decide if a number can be negated or not. Which simply means if you are at an index <code>i</code>, you check if that element along with the element at <code>i+2</code> have the capacity to swallow the element at <code>i+1</code> i.e.</p>
<pre><code>numbers[i] + numbers[i+<span class="hljs-number">2</span>] &gt;= numbers[i+<span class="hljs-number">1</span>  (SWALLOW)
</code></pre><p>If there is a such a possibility, then we directly jump to <code>i+3</code>if we negate element at <code>i</code> because element at <code>i+1</code> and <code>i+2</code> both can’t be negative in such a scenario.</p>
<p>In case the swallow condition is not satisfied and we end up negating the number at index <code>i</code> , then we would jump to index <code>i+2</code> because in any case, two consecutive numbers cannot be negated. So if the number at <code>i</code> was negated, then the number at <code>i+1</code> has to be positive. The swallow check is to see if the number at <code>i+2</code> would definitely have to be positive or if we can exercise the choice of whether to negate or not there.</p>
<p>Have a look at the code for a better understanding.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/xfOALns0BeiZRPCX-3eL6gpcwxRQu4DCn0W7" alt="Image" width="800" height="587" loading="lazy"></p>
<p>Hence, just a single variable i.e. the index is used to define the state of the recursion. So the time and space complexity, both got reduced to half of what they were in the previous solution.</p>
<p>I hope you were able to grasp the working of the algorithm described above and how the dynamic programming technique fits into this problem. I think it’s an interesting problem, because you not only have to use dynamic programming but also the concept of parent pointer to retrace the steps through the optimal solution and get the answer required in the question.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Demystifying Dynamic Programming ]]>
                </title>
                <description>
                    <![CDATA[ By Alaina Kafkes How to construct & code dynamic programming algorithms Maybe you’ve heard about it in preparing for coding interviews. Maybe you’ve struggled through it in an algorithms course. Maybe you’re trying to learn how to code on your own, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/demystifying-dynamic-programming-3efafb8d4296/</link>
                <guid isPermaLink="false">66c348f00bafa8455505c6ac</guid>
                
                    <category>
                        <![CDATA[ Computer Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dynamic Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 31 Jul 2017 18:40:40 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*7QbvB25maQRxi7LGYOAfYw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alaina Kafkes</p>
<h4 id="heading-how-to-construct-amp-code-dynamic-programming-algorithms">How to construct &amp; code dynamic programming algorithms</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*7QbvB25maQRxi7LGYOAfYw.png" alt="Image" width="800" height="400" loading="lazy"></p>
<p>Maybe you’ve heard about it in preparing for coding interviews. Maybe you’ve struggled through it in an algorithms course. Maybe you’re trying to learn how to code on your own, and were told somewhere along the way that it’s important to understand dynamic programming. Using dynamic programming (DP) to write algorithms is as essential as it is feared.</p>
<p>And who can blame those who shrink away from it? Dynamic programming seems intimidating because it is ill-taught. Many tutorials focus on the outcome — <em>explaining</em> the algorithm, instead of the process — <em>finding</em> the algorithm . This encourages memorization, not understanding.</p>
<p>During my algorithms class this year, I pieced together my own process for solving problems that require dynamic programming. Parts of it come from <a target="_blank" href="https://sites.northwestern.edu/hartline/">my algorithms professor</a> (to whom much credit is due!), and parts from my own dissection of dynamic programming algorithms.</p>
<p>But before I share my process, let’s start with the basics. What is dynamic programming, anyway?</p>
<h3 id="heading-dynamic-programming-defined">Dynamic Programming Defined</h3>
<p>Dynamic programming amounts to <strong>breaking down an optimization problem</strong> into simpler sub-problems, and <strong>storing the solution to each sub-problem</strong> so that each sub-problem is only solved once.</p>
<p>To be honest, this definition may not make total sense until you see an example of a sub-problem. That’s okay, it’s coming up in the next section.</p>
<p>What I hope to convey is that DP is a useful technique for optimization problems, those problems that seek the maximum or minimum solution given certain constraints, because it looks through all possible sub-problems and never recomputes the solution to any sub-problem. This guarantees correctness and efficiency, which we cannot say of most techniques used to solve or approximate algorithms. This alone makes DP special.</p>
<p>In the next two sections, I’ll explain what a <strong>sub-problem</strong> is, and then motivate why storing solutions — a technique known as <strong>memoization</strong> — matters in dynamic programming.</p>
<h3 id="heading-sub-problems-on-sub-problems-on-sub-problems">Sub-problems on Sub-problems on Sub-problems</h3>
<p>Sub-problems are smaller versions of the original problem. In fact, sub-problems often look like a reworded version of the original problem. If formulated correctly, sub-problems build on each other in order to obtain the solution to the original problem.</p>
<p>To give you a better idea of how this works, let’s find the sub-problem in an example dynamic programming problem.</p>
<p>Pretend you’re back in the 1950s working on an IBM-650 computer. You know what this means — punchcards! Your job is to man, or woman, the IBM-650 for a day. You’re given a natural number <em>n</em> punchcards to run. Each punchcard <em>i</em> must be run at some predetermined start time _s<em>i</em> and stop running at some predetermined finish time _f<em>i</em>. Only one punchcard can run on the IBM-650 at once. Each punchcard also has an associated value _v<em>i</em> based on how important it is to your company.</p>
<p><strong>Problem</strong>: As the person in charge of the IBM-650, you must determine the optimal schedule of punchcards that maximizes the total value of all punchcards run.</p>
<p>Because I’ll go through this example in great detail throughout this article, I’ll only tease you with its sub-problem for now:</p>
<p><strong>Sub-problem</strong>: The maximum value schedule for punchcards <em>i</em> through <em>n</em> such that the punchcards are sorted by start time.</p>
<p>Notice how the sub-problem breaks down the original problem into components that build up the solution. With the sub-problem, you can find the maximum value schedule for punchcards <em>n-1</em> through <em>n</em>, and then for punchcards <em>n-2</em> through <em>n</em>, and so on. By finding the solutions for every single sub-problem, you can then tackle the original problem itself: the maximum value schedule for punchcards 1 through <em>n</em>. Since the sub-problem looks like the original problem, sub-problems can be used to solve the original problem.</p>
<p>In dynamic programming, after you solve each sub-problem, you must memoize, or store it. Let’s find out why in the following section.</p>
<h3 id="heading-motivating-memoization-with-fibonacci-numbers">Motivating Memoization with Fibonacci Numbers</h3>
<p>When told to implement an algorithm that calculates the <a target="_blank" href="https://www.mathsisfun.com/numbers/fibonacci-sequence.html">Fibonacci value</a> for any given number, what would you do? Most people I know would opt for a <a target="_blank" href="https://softwareengineering.stackexchange.com/questions/25052/in-plain-english-what-is-recursion">recursive algorithm</a> that looks something like this in Python:</p>
<pre><code>def fibonacciVal(n):  <span class="hljs-keyword">if</span> n == <span class="hljs-number">0</span>:    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>  elif n == <span class="hljs-number">1</span>:    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>  <span class="hljs-keyword">else</span>:    <span class="hljs-keyword">return</span> fibonacciVal(n<span class="hljs-number">-1</span>) + fibonacciVal(n<span class="hljs-number">-2</span>)
</code></pre><p>This algorithm accomplishes its purpose, but at a <em>huge</em> cost. For example, let’s look at what this algorithm must calculate in order to solve for n = 5 (abbreviated as F(5)):</p>
<pre><code>F(<span class="hljs-number">5</span>)                      /      \                                     /        \                  /          \               F(<span class="hljs-number">4</span>)          F(<span class="hljs-number">3</span>)            /       \        /   \          F(<span class="hljs-number">3</span>)     F(<span class="hljs-number">2</span>)     F(<span class="hljs-number">2</span>)  F(<span class="hljs-number">1</span>)         /   \     /  \     /   \       F(<span class="hljs-number">2</span>) F(<span class="hljs-number">1</span>) F(<span class="hljs-number">1</span>) F(<span class="hljs-number">0</span>) F(<span class="hljs-number">1</span>) F(<span class="hljs-number">0</span>)       /  \     F(<span class="hljs-number">1</span>) F(<span class="hljs-number">0</span>)
</code></pre><p>The tree above represents each computation that must be made in order to find the Fibonacci value for n = 5. Notice how the sub-problem for n = 2 is solved <strong>thrice.</strong> For a relatively small example (n = 5), that’s a lot of repeated , and wasted, computation!</p>
<p>What if, instead of calculating the Fibonacci value for n = 2 three times, we created an algorithm that calculates it once, stores its value, and accesses the stored Fibonacci value for every subsequent occurrence of n = 2? That’s <em>exactly</em> what memoization does.</p>
<p>With this in mind, I’ve written a dynamic programming solution to the Fibonacci value problem:</p>
<pre><code>def fibonacciVal(n):  memo = [<span class="hljs-number">0</span>] * (n+<span class="hljs-number">1</span>)  memo[<span class="hljs-number">0</span>], memo[<span class="hljs-number">1</span>] = <span class="hljs-number">0</span>, <span class="hljs-number">1</span>  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>, n+<span class="hljs-number">1</span>):    memo[i] = memo[i<span class="hljs-number">-1</span>] + memo[i<span class="hljs-number">-2</span>]  <span class="hljs-keyword">return</span> memo[n]
</code></pre><p>Notice how the solution of the return value comes from the memoization array memo[ ], which is iteratively filled in by the for loop. By “iteratively,” I mean that memo[2] is calculated and stored before memo[3], memo[4], …, and memo[<em>n</em>]. Because memo[ ] is filled in this order, the solution for each sub-problem (n = 3) can be solved by the solutions to its preceding sub-problems (n = 2 and n = 1) because these values were already stored in memo[ ] at an earlier time.</p>
<p>Memoization means no re-computation, which makes for a more efficient algorithm. Thus, memoization ensures that dynamic programming is efficient, but it is choosing the right sub-problem that guarantees that a dynamic program goes through all possibilities in order to find the best one.</p>
<p>Now that we’ve addressed memoization and sub-problems, it’s time to learn the dynamic programming process. Buckle in.</p>
<h3 id="heading-my-dynamic-programming-process">My Dynamic Programming Process</h3>
<h4 id="heading-step-1-identify-the-sub-problem-in-words">Step 1: Identify the sub-problem in words.</h4>
<p>Too often, programmers will turn to writing code <em>before</em> thinking critically about the problem at hand. Not good. One strategy for firing up your brain before you touch the keyboard is using words, English or otherwise, to describe the sub-problem that you have identified within the original problem.</p>
<p>If you’re solving a problem that requires dynamic programming, grab a piece of paper and think about the information that you need to solve this problem. Write out the sub-problem with this in mind.</p>
<p>For example, in the punchcard problem, I stated that the sub-problem can be written as “the maximum value schedule for punchcards <em>i</em> through <em>n</em> such that the punchcards are sorted by start time.” I found this sub-problem by realizing that, in order to determine the maximum value schedule for punchcards 1 through <em>n</em> such that the punchcards are sorted by start time, I would need to find the answer to the following sub-problems:</p>
<ul>
<li>The maximum value schedule for punchcards <em>n-1</em> through <em>n</em> such that the punchcards are sorted by start time</li>
<li>The maximum value schedule for punchcards <em>n-2</em> through <em>n</em> such that the punchcards are sorted by start time</li>
<li>The maximum value schedule for punchcards <em>n-3</em> through <em>n</em> such that the punchcards are sorted by start time</li>
<li>(Et cetera)</li>
<li>The maximum value schedule for punchcards 2 through <em>n</em> such that the punchcards are sorted by start time</li>
</ul>
<p>If you can identify a sub-problem that builds upon previous sub-problems to solve the problem at hand, then you’re on the right track.</p>
<h4 id="heading-step-2-write-out-the-sub-problem-as-a-recurring-mathematical-decision">Step 2: Write out the sub-problem as a recurring mathematical decision.</h4>
<p>Once you’ve identified a sub-problem in words, it’s time to write it out mathematically. Why? Well, the mathematical <strong>recurrence,</strong> or repeated decision, that you find will eventually be what you put into your code. Besides, writing out the sub-problem mathematically vets your sub-problem in words from Step 1. If it is difficult to encode your sub-problem from Step 1 in math, then it may be the wrong sub-problem!</p>
<p>There are two questions that I ask myself every time I try to find a recurrence:</p>
<ul>
<li>What decision do I make at every step?</li>
<li>If my algorithm is at step <em>i</em>, what information would it need to decide what to do in step <em>i+1</em>? (And sometimes: If my algorithm is at step <em>i</em>, what information did it need to decide what to do in step <em>i-1</em>?)</li>
</ul>
<p>Let’s return to the punchcard problem and ask these questions.</p>
<p><strong>What decision do I make at every step?</strong> Assume that the punchcards are sorted by start time, as mentioned previously. For each punchcard that is compatible with the schedule so far (its start time is after the finish time of the punchcard that is currently running), the algorithm must choose between two options: to run, or not to run the punchcard.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*b69mBGpwu6bGJrIlodV6Jw.jpeg" alt="Image" width="465" height="329" loading="lazy">
<em>This dynamic program chooses between two options at each step, just like our dear friend Hamlet!</em></p>
<p><strong>If my algorithm is at step</strong> <strong><em>i</em>, what information would it need to decide what to do in step</strong> <strong><em>i+1</em>?</strong> To decide between the two options, the algorithm needs to know the next compatible punchcard in the order. The next compatible punchcard for a given punchcard <em>p</em> is the punchcard <em>q</em> such that _s<em>q</em> (the predetermined start time for punchcard <em>q</em>) happens after _f<em>p</em> (the predetermined finish time for punchcard <em>p</em>) and the difference between _s<em>q</em> and _f<em>p</em> is minimized. Abandoning mathematician-speak, the next compatible punchcard is the one with the earliest start time after the current punchcard finishes running.</p>
<p><strong>If my algorithm is at step</strong> <strong><em>i</em>, what information did it need to decide what to do in step</strong> <strong><em>i-1</em>?</strong> The algorithm needs to know about future decisions: the ones made for punchcards <em>i</em> through <em>n</em> in order to decide to run or not to run punchcard <em>i-1</em>.</p>
<p>Now that we’ve answered these questions, perhaps you’ve started to form a recurring mathematical decision in your mind. If not, that’s also okay, it becomes easier to write recurrences as you get exposed to more dynamic programming problems.</p>
<p>Without further ado, here’s our recurrence:</p>
<pre><code>OPT(i) = max(v_i + OPT(next[i]), OPT(i+<span class="hljs-number">1</span>))
</code></pre><p>This mathematical recurrence requires some explaining, especially for those who haven’t written one before. I use OPT(<em>i</em>) to represent the maximum value schedule for punchcards <em>i</em> through <em>n</em> such that the punchcards are sorted by start time. Sounds familiar, right? OPT(•) is our sub-problem from Step 1.</p>
<p>In order to determine the value of OPT(<em>i</em>), we consider two options, and we want to take the <em>maximum</em> of these options in order to meet our goal: the <em>maximum</em> value schedule for all punchcards. Once we choose the option that gives the maximum result at step <em>i</em>, we memoize its value as OPT(<em>i</em>).</p>
<p>The two options — to run or not to run punchcard <em>i</em> — are represented mathematically as follows:</p>
<pre><code>v_i + OPT(next[i])
</code></pre><p>This clause represents the decision to run punchcard <em>i</em>. It adds the value gained from running punchcard <em>i</em> to OPT(next[<em>i</em>]), where next[<em>i</em>] represents the next compatible punchcard following punchcard <em>i</em>. OPT(next[<em>i</em>]) gives the maximum value schedule for punchcards next[<em>i</em>] through <em>n</em> such that the punchcards are sorted by start time. Adding these two values together produces maximum value schedule for punchcards <em>i</em> through <em>n</em> such that the punchcards are sorted by start time if punchcard <em>i</em> is run.</p>
<pre><code>OPT(i+<span class="hljs-number">1</span>)
</code></pre><p>Conversely, this clause represents the decision to not run punchcard <em>i</em>. If punchcard <em>i</em> is not run, its value is not gained. OPT(<em>i+1</em>) gives the maximum value schedule for punchcards <em>i+1</em> through <em>n</em> such that the punchcards are sorted by start time. So, OPT(<em>i+1</em>) gives the maximum value schedule for punchcards <em>i</em> through <em>n</em> such that the punchcards are sorted by start time if punchcard <em>i</em> is not run.</p>
<p>In this way, the decision made at each step of the punchcard problems is encoded mathematically to reflect the sub-problem in Step 1.</p>
<h4 id="heading-step-3-solve-the-original-problem-using-steps-1-and-2">Step 3: Solve the original problem using Steps 1 and 2.</h4>
<p>In Step 1, we wrote down the sub-problem for the punchcard problem in words. In Step 2, we wrote down a recurring mathematical decision that corresponds to these sub-problems. How can we solve the original problem with this information?</p>
<pre><code>OPT(<span class="hljs-number">1</span>)
</code></pre><p>It’s that simple. Since the sub-problem we found in Step 1 is the maximum value schedule for punchcards <em>i</em> through <em>n</em> such that the punchcards are sorted by start time, we can write out the solution to the original problem as the maximum value schedule for punchcards 1 through <em>n</em> such that the punchcards are sorted by start time. Since Steps 1 and 2 go hand in hand, the original problem can also be written as OPT(1).</p>
<h4 id="heading-step-4-determine-the-dimensions-of-the-memoization-array-and-the-direction-in-which-it-should-be-filled">Step 4: Determine the dimensions of the memoization array and the direction in which it should be filled.</h4>
<p>Did you find Step 3 deceptively simple? It sure seems that way. You may be thinking, how can OPT(1) be the solution to our dynamic program if it relies on OPT(2), OPT(next[1]), and so on?</p>
<p>You’re correct to notice that OPT(1) relies on the solution to OPT(2). This follows directly from Step 2:</p>
<pre><code>OPT(<span class="hljs-number">1</span>) = max(v_1 + OPT(next[<span class="hljs-number">1</span>]), OPT(<span class="hljs-number">2</span>))
</code></pre><p>But this is not a crushing issue. Think back to Fibonacci memoization example. To find the Fibonacci value for <em>n</em> = 5, the algorithm relies on the fact that the Fibonacci values for <em>n</em> = 4, <em>n</em> = 3, <em>n</em> = 2, <em>n</em> = 1, and <em>n</em> = 0 were already memoized. If we fill in our memoization table in the correct order, the reliance of OPT(1) on other sub-problems is no big deal.</p>
<p>How can we identify the correct direction to fill the memoization table? In the punchcard problem, since we know OPT(1) relies on the solutions to OPT(2) and OPT(next[1]), and that punchcards 2 and next[1] have start times after punchcard 1 due to sorting, we can infer that we need to fill our memoization table from OPT(<em>n</em>) to OPT(1).</p>
<p>How do we determine the dimensions of this memoization array? Here’s a trick: the dimensions of the array are equal to the number and size of the variables on which OPT(•) relies. In the punchcard problem, we have OPT(<em>i</em>), which means that OPT(•) only relies on variable <em>i</em>, which represents the punchcard number. This suggest that our memoization array will be one-dimensional and that its size will be <em>n</em> since there are <em>n</em> total punchcards.</p>
<p>If we know that <em>n</em> = 5, then our memoization array might look like this:</p>
<pre><code>memo = [OPT(<span class="hljs-number">1</span>), OPT(<span class="hljs-number">2</span>), OPT(<span class="hljs-number">3</span>), OPT(<span class="hljs-number">4</span>), OPT(<span class="hljs-number">5</span>)]
</code></pre><p>However, because many programming languages <a target="_blank" href="https://en.wikipedia.org/wiki/Zero-based_numbering">start indexing arrays at 0</a>, it may be more convenient to create this memoization array so that its indices align with punchcard numbers:</p>
<pre><code>memo = [<span class="hljs-number">0</span>, OPT(<span class="hljs-number">1</span>), OPT(<span class="hljs-number">2</span>), OPT(<span class="hljs-number">3</span>), OPT(<span class="hljs-number">4</span>), OPT(<span class="hljs-number">5</span>)]
</code></pre><h4 id="heading-step-5-code-it">Step 5: Code it!</h4>
<p>To code our dynamic program, we put together Steps 2–4. The only new piece of information that you’ll need to write a dynamic program is a base case, which you can find as you tinker with your algorithm.</p>
<p>A dynamic program for the punchcard problem will look something like this:</p>
<pre><code>def punchcardSchedule(n, values, next): # Initialize memoization array - Step <span class="hljs-number">4</span>  memo = [<span class="hljs-number">0</span>] * (n+<span class="hljs-number">1</span>)   # <span class="hljs-built_in">Set</span> base <span class="hljs-keyword">case</span>  memo[n] = values[n]   # Build memoization table <span class="hljs-keyword">from</span> n to <span class="hljs-number">1</span> - Step <span class="hljs-number">2</span>  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(n<span class="hljs-number">-1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">-1</span>):    memo[i] = max(v_i + memo[next[i]], memo[i+<span class="hljs-number">1</span>])  # Return solution to original problem OPT(<span class="hljs-number">1</span>) - Step <span class="hljs-number">3</span>  <span class="hljs-keyword">return</span> memo[<span class="hljs-number">1</span>]
</code></pre><p>Congrats on writing your first dynamic program! Now that you’ve wet your feet, I’ll walk you through a different type of dynamic program.</p>
<h3 id="heading-paradox-of-choice-multiple-options-dp-example">Paradox of Choice: Multiple Options DP Example</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*ZOy2VkYyok5a5YoBEUGMtg.jpeg" alt="Image" width="400" height="477" loading="lazy">
<em>Unrelated to DP, but an accurate depiction of how harrowing multi-option decisions can be.</em></p>
<p>Although the previous dynamic programming example had a two-option decision — to run or not to run a punchcard — some problems require that multiple options be considered before a decision can be made at each step.</p>
<p>Time for a new example.</p>
<p>Pretend you’re selling the friendship bracelets to <em>n</em> customers, and the value of that product increases monotonically. This means that the product has prices {_p<em>1</em>, …, _p<em>n</em>} such that _p_i ≤ p<em>j</em> if customer <em>j</em> comes after customer <em>i</em>. These <em>n</em> customers have values {_v<em>1</em>, …, _v<em>n</em>}. A given customer <em>i</em> will buy a friendship bracelet at price _p<em>i</em> if and only if _p<em>i</em> ≤ _v<em>i</em>; otherwise the revenue obtained from that customer is 0. Assume prices are natural numbers.</p>
<p><strong>Problem</strong>: You must find the set of prices that ensure you the maximum possible revenue from selling your friendship bracelets.</p>
<p>Take a second to think about how you might address this problem before looking at my solutions to Steps 1 and 2.</p>
<h4 id="heading-step-1-identify-the-sub-problem-in-words-1">Step 1: Identify the sub-problem in words.</h4>
<p><strong>Sub-problem</strong>: The maximum revenue obtained from customers <em>i</em> through <em>n</em> such that the price for customer <em>i-1</em> was set at <em>q</em>.</p>
<p>I found this sub-problem by realizing that to determine the maximum revenue for customers 1 through <em>n</em>, I would need to find the answer to the following sub-problems:</p>
<ul>
<li>The maximum revenue obtained from customers <em>n-1</em> through <em>n</em> such that the price for customer <em>n-2</em> was set at <em>q</em>.</li>
<li>The maximum revenue obtained from customers <em>n-2</em> through <em>n</em> such that the price for customer <em>n-3</em> was set at <em>q</em>.</li>
<li>(Et cetera)</li>
</ul>
<p>Notice that I introduced a second variable <em>q</em> into the sub-problem. I did this because, in order to solve each sub-problem, I need to know the price I set for the customer <em>before</em> that sub-problem. Variable <em>q</em> ensures the monotonic nature of the set of prices, and variable <em>i</em> keeps track of the current customer.</p>
<h4 id="heading-step-2-write-out-the-sub-problem-as-a-recurring-mathematical-decision-1">Step 2: Write out the sub-problem as a recurring mathematical decision.</h4>
<p>There are two questions that I ask myself every time I try to find a recurrence:</p>
<ul>
<li>What decision do I make at every step?</li>
<li>If my algorithm is at step <em>i</em>, what information would it need to decide what to do in step <em>i+1</em>? (And sometimes: If my algorithm is at step <em>i</em>, what information would it need to decide what to do in step <em>i-1</em>?)</li>
</ul>
<p>Let’s return to the friendship bracelet problem and ask these questions.</p>
<p><strong>What decision do I make at every step?</strong> I decide at which price to sell my friendship bracelet to the current customer. Since prices must be natural numbers, I know that I should set my price for customer <em>i</em> in the range from <em>q —</em> the price set for customer <em>i-1 —</em> to _v<em>i</em> — the maximum price at which customer <em>i</em> will buy a friendship bracelet.</p>
<p><strong>If my algorithm is at step</strong> <strong><em>i</em>, what information would it need to decide what to do in step</strong> <strong><em>i+1</em>?</strong> My algorithm needs to know the price set for customer <em>i</em> and the value of customer <em>i+1</em> in order to decide at what natural number to set the price for customer <em>i+1</em>.</p>
<p>With this knowledge, I can mathematically write out the recurrence:</p>
<pre><code>OPT(i,q) = max~([Revenue(v_i, a) + OPT(i+<span class="hljs-number">1</span>, a)])
</code></pre><pre><code>such that max~ finds the maximum over all a <span class="hljs-keyword">in</span> the range q ≤ a ≤ v_i
</code></pre><p>Once again, this mathematical recurrence requires some explaining. Since the price for customer <em>i-1</em> is <em>q</em>, for customer <em>i</em>, the price <em>a</em> either stays at integer <em>q</em> or it changes to be some integer between <em>q+1</em> and _v<em>i</em>. To find the total revenue, we add the revenue from customer <em>i</em> to the maximum revenue obtained from customers <em>i+1</em> through <em>n</em> such that the price for customer <em>i</em> was set at <em>a</em>.</p>
<p>In other words, to maximize the total revenue, the algorithm must find the optimal price for customer <em>i</em> by checking all possible prices between <em>q</em> and _v<em>i</em>. If _v<em>i</em> ≤ <em>q</em>, then the price <em>a</em> must remain at <em>q</em>.</p>
<h4 id="heading-what-about-the-other-steps">What about the other steps?</h4>
<p>Working through Steps 1 and 2 is the most difficult part of dynamic programming. As an exercise, I suggest you work through Steps 3, 4, and 5 on your own to check your understanding.</p>
<h3 id="heading-runtime-analysis-of-dynamic-programs">Runtime Analysis of Dynamic Programs</h3>
<p>Now for the fun part of writing algorithms: runtime analysis. I’ll be using big-O notation throughout this discussion . If you’re not yet familiar with big-O, I suggest you read up on it <a target="_blank" href="https://www.interviewcake.com/article/java/big-o-notation-time-and-space-complexity">here</a>.</p>
<p>Generally, a dynamic program’s runtime is composed of the following features:</p>
<ul>
<li>Pre-processing</li>
<li>How many times the for loop runs</li>
<li>How much time it takes the recurrence to run in one for loop iteration</li>
<li>Post-processing</li>
</ul>
<p>Overall, runtime takes the following form:</p>
<pre><code>Pre-processing + Loop * Recurrence + Post-processing
</code></pre><p>Let’s perform a runtime analysis of the punchcard problem to get familiar with big-O for dynamic programs. Here is the punchcard problem dynamic program:</p>
<pre><code>def punchcardSchedule(n, values, next): # Initialize memoization array - Step <span class="hljs-number">4</span>  memo = [<span class="hljs-number">0</span>] * (n+<span class="hljs-number">1</span>)   # <span class="hljs-built_in">Set</span> base <span class="hljs-keyword">case</span>  memo[n] = values[n]   # Build memoization table <span class="hljs-keyword">from</span> n to <span class="hljs-number">1</span> - Step <span class="hljs-number">2</span>  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(n<span class="hljs-number">-1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">-1</span>):    memo[i] = max(v_i + memo[next[i]], memo[i+<span class="hljs-number">1</span>])  # Return solution to original problem OPT(<span class="hljs-number">1</span>) - Step <span class="hljs-number">3</span>  <span class="hljs-keyword">return</span> memo[<span class="hljs-number">1</span>]
</code></pre><p>Let’s break down its runtime:</p>
<ul>
<li>Pre-processing: Here, this means building the the memoization array. O(<em>n</em>).</li>
<li>How many times the for loop runs: O(<em>n</em>).</li>
<li>How much time it takes the recurrence to run in one for loop iteration: The recurrence takes constant time to run because it makes a decision between two options in each iteration. O(1).</li>
<li>Post-processing: None here! O(1).</li>
</ul>
<p>The overall runtime of the punchcard problem dynamic program is O(<em>n</em>) O(<em>n</em>) * O(1) + O(1), or, in simplified form, O(<em>n</em>).</p>
<h3 id="heading-you-did-it">You Did It!</h3>
<p>Well, that’s it — you’re one step closer to becoming a dynamic programming wizard!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*iFMwuyC5ym3f_Ep6L_GEEA.jpeg" alt="Image" width="800" height="969" loading="lazy">
<em>Margaret Hamilton: one of the many programming wizards in our history!</em></p>
<p>One final piece of wisdom: <strong>keep practicing dynamic programming</strong>. No matter how frustrating these algorithms may seem, repeatedly writing dynamic programs will make the sub-problems and recurrences come to you more naturally. Here’s a crowdsourced list of <a target="_blank" href="https://www.quora.com/What-are-the-top-10-most-popular-dynamic-programming-problems-among-interviewers">classic dynamic programming problems</a> for you to try.</p>
<p>So get out there and take your interviews, classes, and <strong>life</strong> (of course) with your newfound dynamic programming knowledge!</p>
<p>Many thanks to <a target="_blank" href="https://stebenn.wordpress.com/">Steven Bennett</a>, <a target="_blank" href="https://medium.com/@eeclaire">Claire Durand</a>, and <a target="_blank" href="https://medium.com/@prithajnath">Prithaj Nath</a> for proofreading this post. Thank you to <a target="_blank" href="https://sites.northwestern.edu/hartline/">Professor Hartline</a> for getting me so excited about dynamic programming that I wrote about it at length.</p>
<p>Enjoy what you read? Spread the love by liking and sharing this piece. Have thoughts or questions? Reach out to me on <a target="_blank" href="https://twitter.com/alainakafkes">Twitter</a> or in the comments below.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
