Competitive Coding

Unit 4: Basic Dynamic Programming

From recursive brute force to elegant optimal solutions โ€” master the art of dynamic programming, solve classic problems, and ace coding interviews at top Indian tech companies.

โฑ๏ธ 8 hrs theory + 6 hrs practice  |  ๐Ÿ’ฐ Earning Potential: โ‚น10,000โ€“โ‚น40,000/month  |  ๐Ÿ“ 30 MCQs (Bloom's Mapped)

๐Ÿ’ผ Jobs this unlocks: Competitive Programmer  |  SDE at FAANG/Product Cos (โ‚น12โ€“40 LPA)  |  Algorithm Engineer

Section A

Opening Hook โ€” The Hidden Algorithm Behind Billions

๐Ÿข How Paytm, Amazon & Google Use Dynamic Programming Every Second

Every time Paytm shows you a cashback offer, a dynamic programming algorithm is running behind the scenes. It evaluates thousands of possible offer combinations and picks the one that maximises your engagement while keeping Paytm's costs optimal. This isn't a simple if-else โ€” it's a variant of the classic Knapsack problem, one of the foundational DP problems you'll learn in this chapter.

Amazon's pricing engine uses DP to dynamically set prices across 10 crore+ products. When you see "โ‚น499" instead of "โ‚น599," a DP-based optimisation decided that price point maximises revenue across the entire product catalog. Google Maps finds the shortest route from your location to any destination using Dijkstra's algorithm โ€” which relies on the optimal substructure property, a core concept of DP.

What if YOU could solve these problems? What if you could look at a complex optimisation problem and say, "I know how to break this down"? That's exactly what this chapter teaches you โ€” the systematic art of Dynamic Programming.

๐Ÿ‡ฎ๐Ÿ‡ณ Paytm๐ŸŒ Amazon๐ŸŒ Google Maps๐Ÿ‡ฎ๐Ÿ‡ณ Flipkart๐Ÿ‡ฎ๐Ÿ‡ณ Swiggy๐Ÿ‡ฎ๐Ÿ‡ณ PhonePe
Every major tech interview at Google, Amazon, Microsoft, and Flipkart includes at least one DP question. In 2024, approximately 40% of coding interview questions on LeetCode were DP-based. Mastering DP is the single biggest differentiator between candidates who crack FAANG interviews and those who don't. The average salary bump for engineers who can solve DP problems fluently is โ‚น5โ€“10 LPA higher than those who can't.
Section B

Learning Outcomes โ€” Bloom's Taxonomy Mapped

Bloom's LevelLearning Outcome
๐Ÿ”ต RememberDefine dynamic programming and list its two key properties: overlapping subproblems and optimal substructure
๐Ÿ”ต RememberState the recurrence relations for Fibonacci, tiling, climbing stairs, and coin change problems
๐Ÿ”ต UnderstandExplain the difference between memoization (top-down) and tabulation (bottom-up) using Fibonacci as an example
๐Ÿ”ต UnderstandIllustrate why naive recursion for Fibonacci is O(2โฟ) while DP reduces it to O(n)
๐ŸŸข ApplyImplement DP solutions for climbing stairs, coin change, and house robber problems in C/C++
๐ŸŸข ApplyTrace and fill DP tables for given inputs step-by-step
๐ŸŸข AnalyzeCompare time and space complexity of recursive vs memoized vs tabulated approaches
๐ŸŸข AnalyzeIdentify whether a given problem exhibits optimal substructure and overlapping subproblems
๐ŸŸ  EvaluateJudge which DP technique (memoization vs tabulation) is better suited for a given problem scenario
๐ŸŸ  EvaluateEvaluate space optimisation opportunities in DP solutions (e.g., O(n) โ†’ O(1))
๐ŸŸ  CreateDesign DP solutions for unseen problems by identifying states, transitions, and base cases
๐ŸŸ  CreateFormulate optimised DP solutions with reduced space complexity for classic problems
Section C

Concept Explanation โ€” Dynamic Programming from Scratch

1. Introduction to Dynamic Programming

Dynamic Programming (DP) is an algorithmic technique that solves complex problems by breaking them into simpler overlapping subproblems and storing their solutions to avoid redundant computation. The term was coined by Richard Bellman in the 1950s.

When should you use DP? Two conditions must BOTH hold:

  1. Overlapping Subproblems โ€” The same subproblems are solved again and again during recursion.
  2. Optimal Substructure โ€” The optimal solution to the problem can be constructed from optimal solutions of its subproblems.

DP = Recursion + Memoization (top-down approach) OR Tabulation (bottom-up approach). Both avoid recomputing the same results.

๐Ÿ“Š Fibonacci: The Gateway to DP

The Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, โ€ฆ

Recurrence: F(n) = F(n-1) + F(n-2), with base cases F(0) = 0, F(1) = 1.

The naive recursive approach recomputes F(3) multiple times when computing F(5). DP stores each result once.

Naive Recursive Fibonacci (Slow โ€” O(2โฟ))

C++
// Naive recursive Fibonacci โ€” exponential time!
int fib(int n) {
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
}
// fib(5) makes 15 function calls!
// fib(40) makes over 300 million calls!

DP Fibonacci โ€” Tabulation (Fast โ€” O(n))

C++
// DP Fibonacci โ€” linear time, linear space
int fib(int n) {
    if (n <= 1) return n;
    int dp[n + 1];
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i <= n; i++)
        dp[i] = dp[i - 1] + dp[i - 2];
    return dp[n];
}
// fib(40) now takes only 40 operations!
DP is like sharing an auto-rickshaw. If you and your friend are going to the same destination, share the ride (reuse the subproblem result) instead of booking two separate autos. Why pay โ‚น200 twice when you can pay โ‚น100 each? DP = don't compute what you've already computed!
If you ever find yourself writing a recursive function where the same arguments are being called multiple times, that's your signal to apply DP. Add a lookup table, and you've just turned an exponential algorithm into a polynomial one.

2. Tiling Problem

Problem: In how many ways can you fill a 2ร—n board with 2ร—1 tiles?

Base cases:

  • n = 1: Only 1 way โ€” place one vertical tile. f(1) = 1
  • n = 2: Two ways โ€” two vertical tiles OR two horizontal tiles. f(2) = 2

Recurrence: For a 2ร—n board, either place a vertical tile (leaving a 2ร—(n-1) board) or place two horizontal tiles (leaving a 2ร—(n-2) board).

f(n) = f(nโˆ’1) + f(nโˆ’2)

DP Table Trace for n = 6

n123456
f(n)1235813

Trace: f(3)=f(2)+f(1)=2+1=3, f(4)=f(3)+f(2)=3+2=5, f(5)=f(4)+f(3)=5+3=8, f(6)=f(5)+f(4)=8+5=13.

C++
#include <iostream>
using namespace std;

int tilingWays(int n) {
    if (n <= 2) return n;
    int dp[n + 1];
    dp[1] = 1;
    dp[2] = 2;
    for (int i = 3; i <= n; i++)
        dp[i] = dp[i - 1] + dp[i - 2];
    return dp[n];
}

int main() {
    int n;
    cout << "Enter n: ";
    cin >> n;
    cout << "Ways to tile 2x" << n << " board: " << tilingWays(n) << endl;
    return 0;
}
The tiling problem produces the Fibonacci sequence! f(1)=1, f(2)=2, f(3)=3, f(4)=5, f(5)=8 โ€ฆ This is a classic example of how seemingly different problems can have the same underlying DP structure. Recognising these patterns is a key competitive programming skill.

3. Tabulation vs Memoization

Memoization (Top-Down): Start from the original problem, recurse downward, and cache results in a table so each subproblem is solved only once.

Tabulation (Bottom-Up): Start from the smallest subproblems (base cases), and iteratively build up to the final answer using a DP table.

ParameterMemoization (Top-Down)Tabulation (Bottom-Up)
ApproachRecursive + lookup cacheIterative + DP table
Starting PointMain problem โ†’ subproblemsBase case โ†’ main problem
Table FillingOn demand (lazy evaluation)All entries filled (eager)
Stack Overflow RiskYes (deep recursion for large n)No (iterative loop)
Extra Stack SpaceO(n) for recursion call stackNone
Code StyleMore intuitive, naturalTypically more efficient

Fibonacci โ€” Memoization (Top-Down)

C++
#include <iostream>
#include <cstring>
using namespace std;

int memo[1001];

int fib(int n) {
    if (n <= 1) return n;
    if (memo[n] != -1) return memo[n]; // already computed!
    memo[n] = fib(n - 1) + fib(n - 2);
    return memo[n];
}

int main() {
    memset(memo, -1, sizeof(memo));
    cout << fib(6) << endl; // Output: 8
    return 0;
}

Fibonacci โ€” Tabulation (Bottom-Up)

C++
int fib(int n) {
    if (n <= 1) return n;
    int dp[n + 1];
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i <= n; i++)
        dp[i] = dp[i - 1] + dp[i - 2];
    return dp[n];
}
// DP Table for fib(6):
// i:     0  1  2  3  4  5  6
// dp[i]: 0  1  1  2  3  5  8
Students often confuse "memoization" with "memorization." Memoization comes from the word "memo" (to note down). It means storing results of expensive function calls and returning the cached result when the same inputs occur again. It has nothing to do with memorising facts!

4. Optimal Substructure Property

Definition: A problem has optimal substructure if an optimal solution to the problem contains optimal solutions to its subproblems.

๐Ÿ“Š When Does Optimal Substructure Hold?

โœ… Shortest Path (YES): The shortest path from A to C through B = shortest(Aโ†’B) + shortest(Bโ†’C). If you know the shortest path to each intermediate point, you can combine them.

โœ… Fibonacci (YES): F(n) = F(n-1) + F(n-2). Each subproblem contributes optimally to the final answer.

โœ… Coin Change (YES): Minimum coins for amount n = 1 + minimum coins for (n โˆ’ coin_value). The subproblem's optimal feeds the parent's optimal.

โŒ Longest Simple Path (NO): In a general graph with no repeated vertices, combining the longest path from Aโ†’B and Bโ†’C may create cycles. The subproblems interfere with each other.

To check optimal substructure, ask yourself: "Can I build the solution to a bigger problem using solutions to smaller problems without them interfering with each other?" If yes, optimal substructure holds.

5. Overlapping Subproblems Property

Definition: A problem has overlapping subproblems when the same subproblems are solved again and again during recursion.

Fibonacci Recursion Tree for F(5)

Tree
                        F(5)
                       /    \
                    F(4)     F(3)       โ† F(3) computed here
                   /    \    /   \
                F(3)   F(2) F(2) F(1)   โ† F(3) also here! F(2) repeated!
               /   \
            F(2)  F(1)                  โ† F(2) again!

F(3) is computed 2 times
F(2) is computed 3 times
F(1) is computed 5 times
Total function calls for F(5): 15 calls!

Why naive recursion is O(2โฟ): The recursion tree is a binary tree. At each level, the number of calls roughly doubles. For F(n), there are approximately 2โฟ total calls.

Why DP makes it O(n): With memoization or tabulation, each value F(0) through F(n) is computed exactly once and stored. Total work = n computations.

Binary Search does NOT have overlapping subproblems โ€” each recursive call works on a completely different half of the array. Merge Sort does NOT have overlapping subproblems โ€” each subarray is unique. Just because a problem uses recursion doesn't mean it needs DP! DP applies only when the same subproblems repeat.

6. Dynamic Programming Process and Techniques

๐Ÿ› ๏ธ The 5-Step DP Framework

Step 1 โ€” Define State: What does dp[i] represent? This is the most critical step. Example: dp[i] = minimum coins needed to make amount i.

Step 2 โ€” Write Recurrence Relation: How does dp[i] relate to previous states? Example: dp[i] = min(dp[i - coin] + 1) for all valid coins.

Step 3 โ€” Identify Base Cases: What are the trivial/smallest answers? Example: dp[0] = 0 (zero coins needed for amount 0).

Step 4 โ€” Decide Iteration Order: Left to right? Bottom-up in a grid? This depends on which states your current state depends on. For coin change: iterate i from 1 to amount.

Step 5 โ€” Optimise Space if Possible: Can you reduce O(n) space to O(1)? For Fibonacci, you only need the last 2 values, not the entire array.

Applying the Framework: Fibonacci

  1. State: dp[i] = the i-th Fibonacci number
  2. Recurrence: dp[i] = dp[i-1] + dp[i-2]
  3. Base cases: dp[0] = 0, dp[1] = 1
  4. Iteration order: Left to right (i = 2, 3, โ€ฆ, n)
  5. Space optimisation: Only need prev2 and prev1 โ†’ O(1) space

Applying the Framework: Climbing Stairs

  1. State: dp[i] = number of ways to reach stair i
  2. Recurrence: dp[i] = dp[i-1] + dp[i-2] (reach stair i from i-1 by 1 step, or from i-2 by 2 steps)
  3. Base cases: dp[0] = 1 (1 way to stay at ground), dp[1] = 1
  4. Iteration order: Left to right (i = 2 to n)
  5. Space optimisation: Same as Fibonacci โ†’ O(1) possible
Before writing code, always write the state definition and recurrence on paper. 80% of DP is figuring out the right state and transition. The coding part is easy once you have the recurrence. In contests, spend 10 minutes thinking, 5 minutes coding.

7. Formulating DP Problems

"Is This a DP Problem?" โ€” Checklist

  • โœ… Does the problem ask for optimal (min/max) or count of ways?
  • โœ… Can I make a choice at each step (take/skip, include/exclude)?
  • โœ… Does the problem have overlapping subproblems?
  • โœ… Does it have optimal substructure?
  • โœ… Can I define a state that captures the essential information?

If you answer YES to most of these, it's likely a DP problem.

Common DP Patterns

PatternDescriptionClassic Examples
Linear DP1D array, dp[i] depends on previous elementsFibonacci, Climbing Stairs, House Robber
Grid DP2D array, dp[i][j] depends on adjacent cellsMin Cost Path, Unique Paths
Interval DPdp[i][j] = optimal for subarray [i..j]Matrix Chain Multiplication
Tree DPDP computed on tree nodes (children โ†’ parent)Diameter of tree, subtree sums
Bitmask DPStates encoded as bitmasks for subset trackingTravelling Salesman Problem
In Codeforces and CodeChef contests, roughly 70% of Div 2 C/D problems are DP-based. Indian competitive programmers like Anudeep Nekkanti and Utkarsh Gupta consistently solve these problems using the patterns listed above. Mastering even just Linear DP and Grid DP covers 60% of contest DP problems.

8. Classic DP Examples

8.1 โ€” Climbing Stairs

Problem: You can climb 1 or 2 stairs at a time. How many distinct ways to reach the top of n stairs?

State: dp[i] = number of distinct ways to reach stair i.

Recurrence: dp[i] = dp[i-1] + dp[i-2]

Base cases: dp[0] = 1, dp[1] = 1

DP Table Trace for n = 5
i012345
dp[i]112358

dp[2]=dp[1]+dp[0]=1+1=2. dp[3]=dp[2]+dp[1]=2+1=3. dp[4]=dp[3]+dp[2]=3+2=5. dp[5]=dp[4]+dp[3]=5+3=8.

C++
#include <iostream>
using namespace std;

int climbStairs(int n) {
    if (n <= 1) return 1;
    int dp[n + 1];
    dp[0] = 1; dp[1] = 1;
    for (int i = 2; i <= n; i++)
        dp[i] = dp[i - 1] + dp[i - 2];
    return dp[n];
}

int main() {
    cout << "Ways to climb 5 stairs: " << climbStairs(5) << endl; // Output: 8
    return 0;
}

Time: O(n)   Space: O(n) โ†’ can optimise to O(1) using two variables.

8.2 โ€” Coin Change (Minimum Coins)

Problem: Given coins of certain denominations, find the minimum number of coins to make a given amount.

State: dp[i] = minimum coins to make amount i.

Recurrence: dp[i] = min(dp[i - coin] + 1) for all coins where coin โ‰ค i

Base case: dp[0] = 0 (zero coins for amount 0)

DP Table Trace: amount = 11, coins = {1, 5, 6}
i01234567891011
dp[i]012341123422

Trace for dp[11]: dp[11] = min(dp[10]+1, dp[6]+1, dp[5]+1) = min(3, 2, 2) = 2. Solution: use coins 5 + 6 = 11.

C++
#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int coinChange(vector<int>& coins, int amount) {
    vector<int> dp(amount + 1, INT_MAX);
    dp[0] = 0;
    for (int i = 1; i <= amount; i++) {
        for (int coin : coins) {
            if (coin <= i && dp[i - coin] != INT_MAX)
                dp[i] = min(dp[i], dp[i - coin] + 1);
        }
    }
    return dp[amount] == INT_MAX ? -1 : dp[amount];
}

int main() {
    vector<int> coins = {1, 5, 6};
    cout << "Min coins for 11: " << coinChange(coins, 11) << endl; // Output: 2
    return 0;
}

Time: O(amount ร— |coins|)   Space: O(amount)

8.3 โ€” House Robber

Problem: You're a robber planning to rob houses along a street. You cannot rob two adjacent houses (alarm triggers). Maximise the total loot.

State: dp[i] = maximum money by considering houses 0 to i.

Recurrence: dp[i] = max(dp[i-1], dp[i-2] + money[i])

Base cases: dp[0] = money[0], dp[1] = max(money[0], money[1])

DP Table Trace: houses = {2, 7, 9, 3, 1}
i01234
money[i]27931
dp[i]27111112

dp[0]=2. dp[1]=max(2,7)=7. dp[2]=max(7, 2+9)=11. dp[3]=max(11, 7+3)=11. dp[4]=max(11, 11+1)=12. Rob houses 0, 2, 4 (โ‚น2+โ‚น9+โ‚น1=โ‚น12).

C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int houseRobber(vector<int>& money) {
    int n = money.size();
    if (n == 0) return 0;
    if (n == 1) return money[0];
    vector<int> dp(n);
    dp[0] = money[0];
    dp[1] = max(money[0], money[1]);
    for (int i = 2; i < n; i++)
        dp[i] = max(dp[i - 1], dp[i - 2] + money[i]);
    return dp[n - 1];
}

int main() {
    vector<int> houses = {2, 7, 9, 3, 1};
    cout << "Max loot: " << houseRobber(houses) << endl; // Output: 12
    return 0;
}

Time: O(n)   Space: O(n) โ†’ can optimise to O(1) with two variables.

8.4 โ€” Min Cost Path in Grid

Problem: Given an mร—n grid where each cell has a cost, find the path from top-left to bottom-right with minimum total cost. You can only move right or down.

State: dp[i][j] = minimum cost to reach cell (i, j).

Recurrence: dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])

Base cases: dp[0][0] = grid[0][0]. First row and first column are cumulative sums.

DP Table Trace: grid = {{1,3,1},{1,5,1},{4,2,1}}
j=0j=1j=2
i=0145
i=1276
i=2687

dp[0][1]=1+3=4, dp[0][2]=4+1=5. dp[1][0]=1+1=2, dp[1][1]=5+min(4,2)=7, dp[1][2]=1+min(5,7)=6. dp[2][0]=4+2=6, dp[2][1]=2+min(7,6)=8, dp[2][2]=1+min(6,8)=7. Path: 1โ†’3โ†’1โ†’1โ†’1.

C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int minCostPath(vector<vector<int>>& grid) {
    int m = grid.size(), n = grid[0].size();
    vector<vector<int>> dp(m, vector<int>(n));
    dp[0][0] = grid[0][0];
    // Fill first row
    for (int j = 1; j < n; j++)
        dp[0][j] = dp[0][j - 1] + grid[0][j];
    // Fill first column
    for (int i = 1; i < m; i++)
        dp[i][0] = dp[i - 1][0] + grid[i][0];
    // Fill rest of DP table
    for (int i = 1; i < m; i++)
        for (int j = 1; j < n; j++)
            dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]);
    return dp[m - 1][n - 1];
}

int main() {
    vector<vector<int>> grid = {{1,3,1},{1,5,1},{4,2,1}};
    cout << "Min cost: " << minCostPath(grid) << endl; // Output: 7
    return 0;
}

Time: O(mร—n)   Space: O(mร—n) โ†’ can optimise to O(n) by reusing a single row.

DP = Sharing an auto-rickshaw. If you and your friend are going to the same destination, share the ride (reuse the subproblem result) instead of booking two separate autos. Why pay โ‚น200 twice when you can pay โ‚น100 each? Every time your DP table reuses a stored value instead of recomputing it, you're "sharing the auto."
Section D

Learn by Doing โ€” 3-Tier Lab Structure

๐ŸŸข Tier 1 โ€” GUIDED TASK: Fibonacci & Climbing Stairs

โฑ๏ธ 45โ€“60 minutesBeginnerZero DP knowledge assumed

Task A: Fibonacci Sequence

Step 1: Write a naive recursive Fibonacci function. Test for n=10, 20, 30, 40. Notice how n=40 takes several seconds.

Step 2: Now add a memo array (initialise to -1). Before computing, check if memo[n] != -1. If so, return cached result.

Step 3: Write a tabulation (bottom-up) version using a for loop and array.

Step 4: Print the first 20 Fibonacci numbers using your DP solution.

Step 5: Compare execution time: Use clock() to measure naive vs DP for n=40.

Task B: Climbing Stairs

Step 1: Implement the climbing stairs DP solution.

Step 2: Test for n=10, 20, 30. Print the complete DP table.

Step 3: Modify to also work for 1, 2, or 3 steps at a time. How does the recurrence change?

Expected Output (Fibonacci first 10): F(0)=0, F(1)=1, F(2)=1, F(3)=2, F(4)=3, F(5)=5, F(6)=8, F(7)=13, F(8)=21, F(9)=34 Expected Output (Climbing Stairs n=5): dp[0]=1, dp[1]=1, dp[2]=2, dp[3]=3, dp[4]=5, dp[5]=8 Ways to climb 5 stairs: 8

๐ŸŸก Tier 2 โ€” SEMI-GUIDED: Coin Change & Tiling

โฑ๏ธ 60โ€“90 minutesIntermediateHints provided, you fill the gaps

Task A: Coin Change with Indian Denominations

Mission: Given coins {1, 2, 5, 10}, find minimum coins needed for every amount from 1 to 100. Print which amounts need the most coins.

Hints:

  1. State: dp[i] = minimum coins for amount i
  2. Initialise dp[0] = 0, everything else = INT_MAX
  3. For each amount, try all 4 coins. Take minimum.
  4. Print the amount that requires the maximum number of coins.

Task B: Extended Tiling Problem

Mission: The classic 2ร—n tiling uses only 2ร—1 tiles. Now also allow 2ร—2 tiles. How does the recurrence change?

Hint: f(n) = f(n-1) + f(n-2) + f(n-2) = f(n-1) + 2ยทf(n-2). Think about what new configurations the 2ร—2 tile enables.

Stretch Goal: Find the 100th term of the extended tiling sequence. Will it overflow int? Use long long.

๐Ÿ”ด Tier 3 โ€” OPEN CHALLENGE: Min Cost Path Visualiser

โฑ๏ธ 90โ€“120 minutesAdvancedNo instructions โ€” real-world challenge

The Brief:

Given a 10ร—10 grid with random costs (1โ€“9), find the minimum cost path from top-left to bottom-right and print the actual path (not just the cost). Visualise the grid with the optimal path marked using asterisks (*).

Requirements:

  1. Generate a 10ร—10 grid with random values 1โ€“9
  2. Apply min-cost-path DP to find the cost
  3. Backtrack from (9,9) to (0,0) to recover the path
  4. Print the grid with path cells marked as *
  5. Print the total cost and the path coordinates
Extra Challenge: Allow diagonal movement too. How does the recurrence change?
Section E

Problem Set โ€” Practice & Mastery

Part 1: DP Table Tracing (5 Problems)

Fill in the complete DP table for each problem. Show your work step-by-step.

T1. Fill the DP table for Fibonacci(8)

i012345678
dp[i]01???????

T2. Fill the DP table for Climbing Stairs(7)

i01234567
dp[i]11??????

T3. Fill the DP table for Coin Change: amount=15, coins={1,5,10}

i0123456789101112131415
dp[i]0???????????????

T4. Fill the DP table for House Robber: houses = {3, 1, 4, 1, 5, 9}

i012345
money[i]314159
dp[i]??????

T5. Fill the DP table for Min Cost Path: grid = {{2,1,3},{6,5,4},{7,8,9}}

j=0j=1j=2
i=0???
i=1???
i=2???

Part 2: Programming Problems (8 Problems)

Implement each in C/C++. Provide time and space complexity.

  1. P1. Fibonacci N-th Term โ€” Compute the n-th Fibonacci number using tabulation. Beginner
  2. P2. Extended Climbing Stairs โ€” Count ways to climb n stairs with steps of 1, 2, or 3 at a time. Beginner
  3. P3. Coin Change (Min Coins) โ€” Given denominations and an amount, find minimum coins needed. Intermediate
  4. P4. House Robber (Circular) โ€” Houses are arranged in a circle (first and last are adjacent). Find max loot. Intermediate
  5. P5. Min Cost Path with Obstacles โ€” Same as min cost path, but some cells are blocked (cost = -1). Intermediate
  6. P6. Longest Increasing Subsequence โ€” Find the length of the LIS in an array. Intermediate
  7. P7. 0/1 Knapsack Problem โ€” Given weights and values, maximise value within weight capacity. Advanced
  8. P8. Edit Distance โ€” Find minimum operations (insert, delete, replace) to convert one string to another. Advanced

Part 3: Industry Application Problems (3 Problems)

  1. I1. Paytm Cashback Optimiser: Given N cashback offers, each with a value and a set of conflicting offers (can't use together), find the maximum total cashback a user can redeem. (Variant of weighted independent set / knapsack.)
  2. I2. Amazon Delivery Route: A city is represented as an mร—n grid. Each cell has a fuel cost. Some cells are blocked (construction). Find the minimum fuel cost route from the warehouse (0,0) to the customer (m-1, n-1).
  3. I3. Flipkart Warehouse Allocation: Flipkart has K warehouses, each with a storage cost per unit. N products need to be stored. Minimise total storage cost such that no warehouse exceeds capacity. (Variant of bin packing / knapsack.)

Part 4: Interview Problems (3 Problems)

  1. V1. Google โ€” Maximum Subarray Sum: Given an integer array, find the contiguous subarray with the largest sum. Implement Kadane's algorithm as a DP solution. State: dp[i] = max subarray sum ending at index i.
  2. V2. Amazon โ€” Word Break: Given a string and a dictionary of words, determine if the string can be segmented into space-separated sequence of dictionary words. State: dp[i] = true if s[0..i-1] can be segmented.
  3. V3. Microsoft โ€” Decode Ways: Given a string of digits, count the number of ways to decode it (A=1, B=2, โ€ฆ, Z=26). State: dp[i] = number of ways to decode s[0..i-1].
Section F

MCQ Assessment Bank โ€” 30 Questions (Bloom's Mapped)

Remember / Identify (Q1โ€“Q5)

Q1

Which two properties must a problem have for Dynamic Programming to be applicable?

  1. Greedy choice + divide and conquer
  2. Overlapping subproblems + optimal substructure
  3. Recursion + binary search
  4. Sorting + searching
Remember
โœ… Answer: (B) โ€” DP requires both overlapping subproblems (same subproblems recur) and optimal substructure (optimal solution built from optimal sub-solutions).
Q2

What is the time complexity of the naive recursive Fibonacci algorithm?

  1. O(n)
  2. O(nยฒ)
  3. O(2โฟ)
  4. O(log n)
Remember
โœ… Answer: (C) O(2โฟ) โ€” The recursion tree branches into two at every level, creating exponential calls.
Q3

In memoization, computed results are stored in a ___.

  1. Binary search tree
  2. Lookup table or array
  3. Stack
  4. Queue
Remember
โœ… Answer: (B) โ€” Memoization uses a lookup table (array or hash map) to cache previously computed results.
Q4

For the tiling problem f(n) = f(n-1) + f(n-2), the base cases are:

  1. f(0) = 0, f(1) = 0
  2. f(1) = 1, f(2) = 2
  3. f(1) = 2, f(2) = 1
  4. f(0) = 1, f(1) = 2
Remember
โœ… Answer: (B) โ€” f(1)=1 (one vertical tile) and f(2)=2 (two vertical or two horizontal).
Q5

Tabulation is also known as the ___ approach.

  1. Top-down
  2. Divide and conquer
  3. Bottom-up
  4. Backtracking
Remember
โœ… Answer: (C) โ€” Tabulation starts from base cases and builds up iteratively, hence called bottom-up.

Understand / Explain (Q6โ€“Q10)

Q6

Why does the naive recursive Fibonacci have exponential time complexity?

  1. It uses too much memory
  2. The same subproblems are computed repeatedly, leading to a binary tree of calls
  3. Fibonacci numbers grow exponentially
  4. It uses division which is slow
Understand
โœ… Answer: (B) โ€” Each call branches into two, and the same F(k) values are recomputed many times. F(2) alone is computed O(2โฟโปยฒ) times.
Q7

Which DP approach fills the table entries "on demand" (lazily)?

  1. Tabulation
  2. Memoization
  3. Greedy
  4. Brute force
Understand
โœ… Answer: (B) โ€” Memoization computes and stores only the subproblems that are actually needed by the recursion, unlike tabulation which fills all entries.
Q8

Why doesn't the "longest simple path" problem in a general graph have optimal substructure?

  1. Because graphs can't have paths
  2. Because combining longest sub-paths may reuse vertices, creating invalid (non-simple) paths
  3. Because the longest path is always unique
  4. Because graphs are always trees
Understand
โœ… Answer: (B) โ€” In a general graph, the longest path from Aโ†’B and Bโ†’C may share intermediate vertices. Combining them would create a non-simple path (with repeated vertices), violating the constraint.
Q9

In the climbing stairs problem, dp[4] = dp[3] + dp[2] because:

  1. We always climb 4 steps at once
  2. We can reach stair 4 either from stair 3 (1 step) or from stair 2 (2 steps)
  3. dp[4] is the sum of all previous values
  4. The problem requires sorting
Understand
โœ… Answer: (B) โ€” To reach stair 4, the last step is either a 1-step from stair 3 or a 2-step from stair 2. So total ways = ways to reach 3 + ways to reach 2.
Q10

Which DP approach is more prone to stack overflow for very large inputs?

  1. Tabulation (bottom-up)
  2. Memoization (top-down)
  3. Both are equally prone
  4. Neither can cause stack overflow
Understand
โœ… Answer: (B) โ€” Memoization uses recursion, which consumes call stack space. For n=10โถ, the recursion depth may exceed the stack limit. Tabulation uses iterative loops and doesn't have this issue.

Apply (Q11โ€“Q15)

Q11

Using the tabulation approach, what is fib(6)?

  1. 5
  2. 6
  3. 8
  4. 13
Apply
โœ… Answer: (C) 8 โ€” dp: 0,1,1,2,3,5,8. fib(6)=8.
Q12

Coin change with coins={1,3,4}, amount=6. What is dp[6]?

  1. 1
  2. 2
  3. 3
  4. 6
Apply
โœ… Answer: (B) 2 โ€” dp[6]=min(dp[5]+1, dp[3]+1, dp[2]+1)=min(3,2,3)=2. Use two coins of 3 (3+3=6).
Q13

House Robber with houses = {6, 7, 1, 30}. Maximum loot?

  1. 30
  2. 36
  3. 37
  4. 7
Apply
โœ… Answer: (B) 36 โ€” dp[0]=6, dp[1]=max(6,7)=7, dp[2]=max(7,6+1)=7, dp[3]=max(7,7+30)=37. Wait โ€” dp[3]=max(dp[2], dp[1]+30)=max(7,7+30)=37. Actually the answer should be 37, not 36. Let me re-check: {6,7,1,30}. dp[0]=6, dp[1]=max(6,7)=7, dp[2]=max(7,6+1)=7, dp[3]=max(7,7+30)=37. Rob houses 1 and 3 (7+30=37). Answer: (C) 37.
Q14

For climbing stairs, what is dp[3]? (dp[0]=1, dp[1]=1)

  1. 2
  2. 3
  3. 4
  4. 5
Apply
โœ… Answer: (B) 3 โ€” dp[2]=dp[1]+dp[0]=2. dp[3]=dp[2]+dp[1]=2+1=3. The 3 ways are: {1,1,1}, {1,2}, {2,1}.
Q15

Min cost path, grid={{1,2},{3,4}}. What is dp[1][1]?

  1. 4
  2. 7
  3. 8
  4. 10
Apply
โœ… Answer: (B) 7 โ€” dp[0][0]=1, dp[0][1]=1+2=3, dp[1][0]=1+3=4. dp[1][1]=4+min(3,4)=4+3=7.

Analyze (Q16โ€“Q20)

Q16

For computing Fibonacci(1000), which approach is safer?

  1. Memoization โ€” it's more intuitive
  2. Tabulation โ€” it avoids stack overflow from deep recursion
  3. Naive recursion โ€” it's simpler code
  4. Both are equally safe
Analyze
โœ… Answer: (B) โ€” Memoization with recursion depth 1000 risks stack overflow on many systems (default stack ~1MB). Tabulation uses a simple for-loop with no recursion.
Q17

A function makes calls f(n-1) and f(n/2). Does it have overlapping subproblems?

  1. No โ€” the subproblems are always different
  2. Yes โ€” values like f(1), f(2) will be reached via multiple paths
  3. Only if n is even
  4. Cannot be determined
Analyze
โœ… Answer: (B) โ€” Consider f(8): f(7) and f(4). f(7) calls f(6) and f(3). f(6) calls f(5) and f(3). f(3) is already repeated. Small values like f(1), f(2) are reached via many paths.
Q18

Solution A: O(nยฒ) time, O(n) space. Solution B: O(n log n) time, O(nยฒ) space. For n=10โถ, which is better?

  1. Solution A โ€” less space
  2. Solution B โ€” faster execution time
  3. Both are equivalent
  4. Neither will work
Analyze
โœ… Answer: (B) โ€” For n=10โถ: A takes 10ยนยฒ operations (TLE), B takes ~2ร—10โท operations (fast). B's O(nยฒ) space = ~4TB which is too much. Actually, for n=10โถ, O(nยฒ) space = 10ยนยฒ bytes which is impractical. So the answer depends on constraints. In competitive programming, time is usually the bottleneck, making (B) preferable if space fits in memory.
Q19

In House Robber, why can't we use a greedy approach (always pick the largest)?

  1. Greedy always works for this problem
  2. Picking the largest may block two adjacent high-value houses โ€” e.g., {1, 100, 1, 100}
  3. Greedy is faster than DP
  4. DP can't solve this problem
Analyze
โœ… Answer: (B) โ€” For {1,100,1,100}: Greedy picks 100 (index 1), then can't pick index 0 or 2. Picks 100 (index 3). Total=200. Actually greedy works here. But for {5,1,1,5}: greedy picks 5 (index 0), skips 1,1, picks 5 (index 3)=10. DP also gives 10. Consider {3,10,3,1,2}: greedy picks 10, can't pick 3 or 3. Picks 2. Total=12. DP: dp[0]=3, dp[1]=10, dp[2]=max(10,3+3)=10, dp[3]=max(10,10+1)=11, dp[4]=max(11,10+2)=12. Same. The key counterexample is when greedy with "skip one, pick next" fails due to non-local effects.
Q20

Compare Fibonacci(5) recursion tree vs Binary Search on 32 elements. Which has overlapping subproblems?

  1. Both have overlapping subproblems
  2. Only Fibonacci โ€” Binary Search explores unique sub-arrays each time
  3. Only Binary Search
  4. Neither has overlapping subproblems
Analyze
โœ… Answer: (B) โ€” Fibonacci's tree shows F(3), F(2) computed multiple times. Binary Search on each call processes a different half of the array โ€” no subproblem repeats.

Evaluate (Q21โ€“Q25)

Q21

A student writes dp[i] = dp[i-1] + dp[i-3] for climbing stairs (1 or 2 steps). What's wrong?

  1. Nothing โ€” it's correct
  2. Should be dp[i-1] + dp[i-2], since you can take 1 or 2 steps, not 1 or 3
  3. Should be dp[i-2] + dp[i-3]
  4. Should be dp[i-1] ร— dp[i-2]
Evaluate
โœ… Answer: (B) โ€” With steps of size 1 or 2, you reach stair i from stair i-1 (1 step) or i-2 (2 steps). dp[i-3] would be for 3-step jumps, which aren't allowed.
Q22

A student optimises Fibonacci by using only 2 variables instead of an array. Does this sacrifice correctness?

  1. Yes โ€” we lose information needed for the answer
  2. No โ€” we only ever need the last two values, so this is valid O(1) space optimisation
  3. It works for small n but fails for large n
  4. It changes the time complexity to O(nยฒ)
Evaluate
โœ… Answer: (B) โ€” Since dp[i] only depends on dp[i-1] and dp[i-2], we can use two variables prev1 and prev2. This is a standard space optimisation that maintains correctness.
Q23

A student claims: "All recursive problems can be solved with DP." Is this correct?

  1. Yes โ€” recursion and DP are the same thing
  2. No โ€” DP only applies when there are overlapping subproblems and optimal substructure
  3. Yes โ€” just add memoization to any recursion
  4. No โ€” DP can only solve math problems
Evaluate
โœ… Answer: (B) โ€” Merge sort uses recursion but has no overlapping subproblems. Adding memoization to merge sort wouldn't help because each subarray is unique. DP specifically requires both properties.
Q24

For coin change with coins={1,5,10,25}, is the greedy approach (always pick the largest coin) always optimal?

  1. Yes โ€” and this is true for all coin systems
  2. Yes โ€” for this specific set, greedy works. But it fails for sets like {1,3,4}
  3. No โ€” greedy never works for coin change
  4. No โ€” only DP works for any coin problem
Evaluate
โœ… Answer: (B) โ€” For canonical coin systems (like Indian currency), greedy works. But for {1,3,4} with amount=6: greedy gives 4+1+1=3 coins, while DP gives 3+3=2 coins. DP is always correct; greedy isn't guaranteed.
Q25

Is it worth converting an O(n) space DP solution to O(1) space if n is always less than 100?

  1. Absolutely โ€” every optimisation matters
  2. Probably not โ€” the space saved is negligible and the code becomes less readable
  3. Yes โ€” it changes the time complexity too
  4. No โ€” O(1) space is impossible for DP
Evaluate
โœ… Answer: (B) โ€” For n<100, an array of 100 integers uses only 400 bytes. The space optimisation saves negligible memory but makes the code harder to read and debug. Premature optimisation is the root of all evil (Knuth).

Create (Q26โ€“Q30)

Q26

Write the recurrence for: Minimum cost to paint n houses with 3 colours (R, G, B), where no two adjacent houses can have the same colour. cost[i][c] = cost to paint house i with colour c.

  1. dp[i][c] = cost[i][c] + min(dp[i-1][other colours])
  2. dp[i][c] = cost[i][c] + dp[i-1][c]
  3. dp[i][c] = min(cost[i][0], cost[i][1], cost[i][2])
  4. dp[i] = cost[i] + dp[i-2]
Create
โœ… Answer: (A) โ€” dp[i][R] = cost[i][R] + min(dp[i-1][G], dp[i-1][B]). Similarly for G and B. The constraint "no adjacent same colour" means we must pick from the other two colours for the previous house.
Q27

Design the state definition for: Maximum profit from stock prices with at most 2 transactions.

  1. dp[i] = max profit on day i
  2. dp[i][j][k] where i=day, j=transactions used, k=holding/not-holding stock
  3. dp[i] = prices[i] - prices[0]
  4. dp[i][j] = profit using j stocks on day i
Create
โœ… Answer: (B) โ€” We need to track three things: which day we're on (i), how many transactions we've completed (j = 0,1,2), and whether we currently hold a stock (k = 0 or 1). This gives us the state dp[i][j][k].
Q28

Max sum of non-adjacent elements in a circular array. How to handle the circular constraint?

  1. Run House Robber once on the full array
  2. Run House Robber twice: once on arr[0..n-2], once on arr[1..n-1], take the maximum
  3. Sort the array first, then apply House Robber
  4. Use a 2D DP table
Create
โœ… Answer: (B) โ€” In a circular arrangement, house 0 and house n-1 are adjacent. So either we include house 0 (exclude house n-1) or include house n-1 (exclude house 0). Run House Robber on arr[0..n-2] and arr[1..n-1], take the maximum.
Q29

Create a space-optimised climbing stairs solution using only 2 variables. Which code is correct?

  1. prev=1; curr=1; for i=2..n: next=curr+prev; prev=curr; curr=next;
  2. a=0; b=1; for i=0..n: a=a+b;
  3. x=1; for i=0..n: x=2*x;
  4. a=1; b=1; for i=2..n: a=a+b; swap(a,b);
Create
โœ… Answer: (A) โ€” We maintain prev (dp[i-2]) and curr (dp[i-1]). Each iteration: next = curr+prev, then shift: prev=curr, curr=next. After the loop, curr holds dp[n].
Q30

Design DP for: Count the number of ways to make change for amount n with given coins (not minimum, but count of combinations). What's the recurrence?

  1. dp[i] = dp[i-1] + dp[i-2]
  2. dp[i] += dp[i - coin] for each coin (process coins in outer loop to avoid counting permutations)
  3. dp[i] = min(dp[i-coin]+1)
  4. dp[i][j] = dp[i-1][j] + dp[i][j-1]
Create
โœ… Answer: (B) โ€” For counting combinations (not permutations), iterate coins in the outer loop: for each coin, for i = coin to n: dp[i] += dp[i - coin]. Base case: dp[0] = 1. This ensures each combination is counted once.
Section G

Short Answer Questions (8 Questions)

Q1. Define dynamic programming in your own words. What two properties must a problem have for DP to apply? (4 marks)

Answer: Dynamic Programming is an algorithmic paradigm that solves complex optimisation or counting problems by breaking them into smaller overlapping subproblems, solving each subproblem only once, and storing the result to avoid redundant computation. The two essential properties are:

1. Overlapping Subproblems: The problem can be broken into subproblems which are reused multiple times. Example: Fibonacci โ€” F(3) is needed by both F(5) and F(4).

2. Optimal Substructure: The optimal solution to the overall problem can be constructed from optimal solutions to its subproblems. Example: Shortest path โ€” the shortest path from A to C through B combines the shortest paths Aโ†’B and Bโ†’C.

Q2. Write the recurrence relation and base cases for the tiling problem (2ร—n board, 2ร—1 tiles). Trace the DP table for n=7. (5 marks)

Recurrence: f(n) = f(n-1) + f(n-2)

Base Cases: f(1) = 1, f(2) = 2

Logic: For a 2ร—n board, either place a vertical tile (leaving 2ร—(n-1)) or two horizontal tiles (leaving 2ร—(n-2)).

DP Table for n=7:

n1234567
f(n)123581321

f(3)=2+1=3, f(4)=3+2=5, f(5)=5+3=8, f(6)=8+5=13, f(7)=13+8=21.

Q3. Compare memoization and tabulation with at least 5 differences. Which would you prefer for 10โต states? (5 marks)

ParameterMemoizationTabulation
DirectionTop-down (problem โ†’ subproblems)Bottom-up (base โ†’ answer)
ImplementationRecursive + lookup cacheIterative + DP array
Table fillingLazy โ€” only needed entriesEager โ€” all entries filled
Stack overflowRisk for large nNo risk (iterative)
Extra spaceO(n) recursion stackNo extra stack space

For 10โต states: Prefer tabulation. Recursion depth of 10โต will likely cause stack overflow. Tabulation handles this safely with a simple loop.

Q4. Draw the recursion tree for Fibonacci(5). Circle repeated subproblems. How many calls without DP vs with DP? (5 marks)

                    F(5)
                   /    \
                F(4)    F(3)  โ† REPEATED
               /   \    /  \
            F(3)  F(2) F(2) F(1)  โ† F(2) REPEATED
           /  \
         F(2) F(1)  โ† F(2) REPEATED

Without DP: 15 total function calls. F(2) computed 3 times, F(3) computed 2 times.

With DP (memoization): Only 9 calls (5 unique values + 4 cache hits). With tabulation: exactly 6 operations (fill dp[0] through dp[5]).

Q5. Explain the 5-step DP framework with the coin change example: coins={1,5,10}, amount=12. (6 marks)

Step 1 โ€” Define State: dp[i] = minimum number of coins to make amount i.

Step 2 โ€” Recurrence: dp[i] = min(dp[i-1]+1, dp[i-5]+1, dp[i-10]+1) for valid indices.

Step 3 โ€” Base Case: dp[0] = 0 (zero coins for zero amount).

Step 4 โ€” Iteration Order: Left to right, i from 1 to 12.

Step 5 โ€” Space Optimisation: Cannot easily optimise here since dp[i] depends on dp[i-1], dp[i-5], dp[i-10] โ€” need the full array.

Answer: dp[12] = min(dp[11]+1, dp[7]+1, dp[2]+1) = min(3, 3, 3) = 3 coins. Solution: 10+1+1 = 12.

Q6. What is optimal substructure? Give one example where it holds and one where it doesn't. (4 marks)

Definition: A problem has optimal substructure if the optimal solution contains optimal solutions to its subproblems.

Holds โ€” Shortest Path: The shortest path from A to C passing through B = shortest(Aโ†’B) + shortest(Bโ†’C). The subproblem solutions combine correctly.

Doesn't Hold โ€” Longest Simple Path: In a general graph, combining the longest simple path Aโ†’B and Bโ†’C may create cycles (revisit vertices), giving an invalid result. The subproblems interfere.

Q7. Solve House Robber for {2, 7, 9, 3, 1}. Show DP table and trace which houses are robbed. (5 marks)

i01234
money[i]27931
dp[i]27111112

dp[0]=2, dp[1]=max(2,7)=7, dp[2]=max(7,2+9)=11, dp[3]=max(11,7+3)=11, dp[4]=max(11,11+1)=12.

Backtrack: dp[4]=12=dp[2]+money[4]=11+1 โ†’ rob house 4. dp[2]=11=dp[0]+money[2]=2+9 โ†’ rob house 2. dp[0]=2=money[0] โ†’ rob house 0.

Houses robbed: 0, 2, 4 (values: 2+9+1 = 12).

Q8. Explain why greedy fails for coin change with coins={1,3,4} and amount=6, but DP gives the correct answer. (4 marks)

Greedy approach: Always pick the largest coin first. For amount=6: pick 4 (remaining=2), pick 1 (remaining=1), pick 1 (remaining=0). Total: 3 coins (4+1+1).

DP approach: dp[6] = min(dp[5]+1, dp[3]+1, dp[2]+1) = min(2+1, 1+1, 2+1) = 2 coins (3+3=6).

Why greedy fails: Greedy makes locally optimal choices (pick largest coin) but misses the globally optimal combination. By picking 4 first, it commits to a path that requires 3 coins. DP explores all possibilities and finds that two 3s is better. Greedy doesn't "look ahead" โ€” DP does.

Section H

Long Answer Questions (3 Questions)

Q1. Dynamic Programming Comprehensive (10 marks)

(a) Define DP and explain both properties with examples. (3 marks)

Dynamic Programming is an algorithmic technique for solving optimisation and counting problems by breaking them into overlapping subproblems and storing solutions to avoid recomputation.

Overlapping Subproblems: Same sub-computations recur. In Fibonacci, F(3) is needed by both F(5) and F(4).

Optimal Substructure: Optimal answer = combination of optimal sub-answers. In coin change, min coins for amount 11 = 1 + min coins for (11 โˆ’ coin).

(b) Solve Coin Change for coins={1,5,6,9}, amount=11. Show DP table, trace, write code. (4 marks)

i01234567891011
dp[i]012341123122

dp[11] = min(dp[10]+1, dp[6]+1, dp[5]+1, dp[2]+1) = min(3, 2, 2, 3) = 2. Use coins 5+6 or 9+? โ†’ Actually dp[2]+1=3 (coin 9: dp[11-9]=dp[2]=2, so 2+1=3). dp[5]+1=1+1=2, dp[6]+1=1+1=2. Solution: 5+6=11 (2 coins).

C++
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main() {
    vector<int> coins = {1,5,6,9};
    int amount = 11;
    vector<int> dp(amount+1, INT_MAX);
    dp[0] = 0;
    for(int i=1; i<=amount; i++)
        for(int c : coins)
            if(c<=i && dp[i-c]!=INT_MAX)
                dp[i] = min(dp[i], dp[i-c]+1);
    cout << dp[amount] << endl; // Output: 2
}

(c) Optimise space complexity and explain trade-offs. (3 marks)

The coin change DP already uses O(amount) space, which is optimal for this problem โ€” we cannot reduce it further because dp[i] depends on dp[i-coin] where coin can be any denomination (not just the last 1โ€“2 values). Unlike Fibonacci where O(1) space works, coin change needs the full array. The trade-off: we sacrifice the ability to recover which coins were used (for that, we'd need an additional parent array).

Q2. DP Problem Solving โ€” Min Cost Path (10 marks)

(a) Explain the 5-step DP framework. (2 marks)

1. Define state (what dp[i][j] means). 2. Write recurrence. 3. Set base cases. 4. Decide iteration order. 5. Optimise space if possible.

(b) Apply to a 4ร—4 grid. Show complete DP table. (4 marks)

Grid: {{1,3,5,8},{4,2,1,7},{4,3,2,3},{3,6,5,2}}

State: dp[i][j] = min cost to reach (i,j). Recurrence: dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]).

j=0j=1j=2j=3
i=014917
i=156714
i=299912
i=312151414

Answer: dp[3][3] = 14.

(c) Print the actual path using backtracking. (4 marks)

C++
// After building DP table, backtrack from (m-1,n-1) to (0,0)
void printPath(vector<vector<int>>& dp, int m, int n) {
    vector<pair<int,int>> path;
    int i = m-1, j = n-1;
    path.push_back({i, j});
    while (i > 0 || j > 0) {
        if (i == 0) j--;
        else if (j == 0) i--;
        else if (dp[i-1][j] < dp[i][j-1]) i--;
        else j--;
        path.push_back({i, j});
    }
    for (int k = path.size()-1; k >= 0; k--)
        cout << "(" << path[k].first << "," << path[k].second << ") ";
}

Q3. Comparative Analysis โ€” Fibonacci Three Ways (10 marks)

(a) Code for all three approaches. (4 marks)

C++
// 1. Recursive
int fibRec(int n) {
    if(n<=1) return n;
    return fibRec(n-1) + fibRec(n-2);
}

// 2. Memoized
int memo[1000001];
int fibMemo(int n) {
    if(n<=1) return n;
    if(memo[n]!=-1) return memo[n];
    return memo[n] = fibMemo(n-1) + fibMemo(n-2);
}

// 3. Tabulated
int fibTab(int n) {
    if(n<=1) return n;
    int dp[n+1];
    dp[0]=0; dp[1]=1;
    for(int i=2;i<=n;i++) dp[i]=dp[i-1]+dp[i-2];
    return dp[n];
}

(b) Comparison table. (3 marks)

ApproachTimeSpaceStack Safe?
RecursiveO(2โฟ)O(n) stackNo (stack overflow for n>30)
MemoizedO(n)O(n) array + O(n) stackNo (stack overflow for n>10โด)
TabulatedO(n)O(n) arrayYes

(c) For n=10โถ, use tabulation with O(1) space. (3 marks)

C++
long long fibOpt(int n) {
    if(n<=1) return n;
    long long prev2 = 0, prev1 = 1, curr;
    for(int i=2; i<=n; i++) {
        curr = prev1 + prev2;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}

This is O(n) time, O(1) space. Safe for n=10โถ. Note: actual Fibonacci values overflow even long long around n=93, so for very large n you'd need big-integer arithmetic or compute modulo a prime.

Section I

Lab Program โ€” Tiling Problem

๐Ÿ”ฌ Lab Program: Tiling Problem (2ร—n board with 2ร—1 tiles)

๐Ÿ–ฅ๏ธ Language: C++Intermediateโฑ๏ธ 30 minutes

Problem Statement

Given a 2ร—n board, find the number of ways to fill it completely using 2ร—1 tiles. Tiles can be placed horizontally or vertically.

Algorithm

  1. Define dp[i] = number of ways to tile a 2ร—i board.
  2. Base cases: dp[1] = 1, dp[2] = 2.
  3. Recurrence: dp[i] = dp[i-1] + dp[i-2] for i โ‰ฅ 3.
  4. Iterate from i=3 to n, filling the DP table.
  5. Return dp[n].

Complete Code

C++
#include <iostream>
using namespace std;

int tilingWays(int n) {
    if (n == 1) return 1;
    if (n == 2) return 2;

    int dp[n + 1];
    dp[1] = 1;
    dp[2] = 2;

    for (int i = 3; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }

    return dp[n];
}

int main() {
    int n;
    cout << "Enter the value of n: ";
    cin >> n;

    cout << "Number of ways to tile a 2x" << n
         << " board: " << tilingWays(n) << endl;

    // Print DP table for reference
    cout << "\nDP Table:\n";
    cout << "n\t| Ways\n";
    cout << "--------|------\n";
    for (int i = 1; i <= n; i++) {
        cout << i << "\t| " << tilingWays(i) << "\n";
    }

    return 0;
}

Sample Output (n = 10)

Enter the value of n: 10 Number of ways to tile a 2x10 board: 89 DP Table: n | Ways --------|------ 1 | 1 2 | 2 3 | 3 4 | 5 5 | 8 6 | 13 7 | 21 8 | 34 9 | 55 10 | 89

Time Complexity: O(n) โ€” single pass through the array.

Space Complexity: O(n) for the DP array. Can be optimised to O(1) using two variables.

Viva Questions & Answers

V1. Why is the tiling problem similar to Fibonacci?

Both have the same recurrence: f(n) = f(n-1) + f(n-2). The tiling problem with base cases f(1)=1, f(2)=2 produces the Fibonacci sequence shifted by one position. This is because at each step, you have exactly two choices (vertical tile or horizontal pair), just like the two branches in Fibonacci.

V2. What happens if we also allow 1ร—1 tiles?

If 1ร—1 tiles are allowed on a 2ร—n board, the problem becomes more complex. You can no longer use a simple 1D DP. You'd need to track the state of each column (whether the bottom cell is filled or not), leading to a 2D state or bitmask DP approach.

V3. Can this problem be solved using matrix exponentiation?

Yes! Since f(n) = f(n-1) + f(n-2), we can write it as a matrix equation: [[f(n)],[f(n-1)]] = [[1,1],[1,0]]^(n-1) ร— [[f(2)],[f(1)]]. Using matrix exponentiation, this gives O(log n) time complexity โ€” much faster than O(n) for very large n.

V4. What are the base cases and why?

f(1)=1: A 2ร—1 board can only be filled with one vertical tile. f(2)=2: A 2ร—2 board can be filled either with two vertical tiles or two horizontal tiles. These are the smallest boards that can be fully tiled.

V5. How would you extend this to a 3ร—n board?

A 3ร—n tiling is much harder. The recurrence is no longer simple. For a 3ร—n board with 2ร—1 tiles: solutions exist only for even n. The recurrence involves multiple states tracking which cells in a column are filled. It requires profile DP (bitmask DP on column profiles). The simple f(n)=f(n-1)+f(n-2) doesn't apply.

Section J

Industry Spotlight โ€” A Day in the Life

๐Ÿ‘ฉโ€๐Ÿ’ป Sneha Gupta, 27 โ€” Algorithm Engineer at Flipkart, Bangalore

Background: B.Tech from NIT Warangal. Started competitive programming in 2nd year on CodeChef (5-star rated). Solved 500+ DP problems on LeetCode. Interned at Amazon for 2 months. Joined Flipkart through an off-campus referral from a CP community friend.

A Typical Day:

9:00 AM โ€” Morning standup with the pricing algorithms team. Review yesterday's price optimisation metrics.

10:00 AM โ€” Work on the dynamic pricing algorithm using DP to optimise prices across 50,000 product categories. The core is a knapsack variant that maximises revenue subject to margin constraints.

11:30 AM โ€” Code review for a colleague's warehouse allocation solution โ€” a variant of the bin-packing problem solved with DP.

1:00 PM โ€” Lunch at Flipkart's cafeteria. Discuss last weekend's CodeChef Long contest problem โ€” a tree DP problem that only 200 people solved.

2:00 PM โ€” Design a new DP-based recommendation engine that suggests product bundles (e.g., "phone + cover + screen guard" combos that maximise cart value).

4:00 PM โ€” Mentor 2 junior developers on DP thinking patterns. Today's topic: how to identify states and transitions.

5:30 PM โ€” Solve 2 LeetCode DP problems (maintains a daily streak of 400+ days). Today: "Burst Balloons" and "Palindrome Partitioning II."

DetailInfo
Tools Used DailyC++, Python, LeetCode, CodeChef, Git, VS Code, Internal ML platform
Entry Salary (2024)โ‚น12โ€“18 LPA + stocks
Mid-Level (3โ€“5 yrs)โ‚น25โ€“40 LPA
Senior (7+ yrs)โ‚น50โ€“80 LPA
Companies HiringFlipkart, Amazon, Google, Microsoft, Goldman Sachs, Tower Research Capital, DE Shaw, Uber, Razorpay
Section K

Earn With It โ€” Freelance & Income Roadmap

๐Ÿ’ฐ Your Earning Path After This Chapter

Portfolio Piece: "Dynamic Programming Problem Solver" โ€” a GitHub repo with 20+ solved DP problems, each with explanation, DP table trace, and complexity analysis.

Beginner Gig Ideas:

โ€ข DP tutoring for coding interview prep โ€” โ‚น500โ€“โ‚น1,500/hour

โ€ข Competitive programming coaching for juniors โ€” โ‚น3,000โ€“โ‚น8,000/month per student

โ€ข Creating DP problem sets for coaching institutes โ€” โ‚น5,000โ€“โ‚น15,000/set

โ€ข Content writing for coding education platforms โ€” โ‚น2,000โ€“โ‚น5,000/article

PlatformBest ForTypical Rate
Topmate1:1 coding mentorship sessionsโ‚น500โ€“โ‚น2,000/session
PreplacedInterview prep coachingโ‚น1,000โ€“โ‚น3,000/session
YouTubeDP tutorial video seriesโ‚น5,000โ€“โ‚น50,000/month (after growth)
FiverrCoding problem solutions & explanationsโ‚น500โ€“โ‚น3,000/problem
Local CoachingIn-person tutoring at coaching centresโ‚น3,000โ€“โ‚น10,000/month

โฑ๏ธ Time to First Earning: 1โ€“2 weeks (if you can solve 50+ DP problems confidently and create a Topmate profile)

The highest ROI skill in competitive coding is DP. Most coding interviews at FAANG companies test DP. If you can teach it, you can charge premium rates. Start with free sessions on Topmate, get 5-star reviews, then increase rates. A student who can teach DP is worth more than one who can only solve it โ€” because teaching requires deeper understanding.
Section L

Chapter Summary

๐Ÿ“‹ Key Takeaways โ€” Basic Dynamic Programming

  • Dynamic Programming solves problems by storing solutions to overlapping subproblems, avoiding redundant computation.
  • Two key properties: Overlapping Subproblems + Optimal Substructure. Both must hold for DP to apply.
  • Two approaches: Memoization (top-down, recursive + cache) and Tabulation (bottom-up, iterative DP table).
  • 5-Step Framework: Define state โ†’ Write recurrence โ†’ Base cases โ†’ Iteration order โ†’ Space optimisation.
  • Classic problems covered: Fibonacci, Tiling (2ร—n), Climbing Stairs, Coin Change, House Robber, Min Cost Path.
  • Tiling recurrence: f(n) = f(n-1) + f(n-2). Same structure as Fibonacci.
  • Coin Change recurrence: dp[i] = min(dp[i-coin]+1) for all valid coins. Greedy doesn't always work.
  • House Robber recurrence: dp[i] = max(dp[i-1], dp[i-2]+money[i]). Can't rob adjacent houses.
  • Min Cost Path recurrence: dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]).
  • Time complexity: Most 1D DP is O(n). Grid DP is O(mร—n). Coin change is O(amount ร— |coins|).
  • Space optimisation: Fibonacci/Stairs: O(n) โ†’ O(1). Grid DP: O(mร—n) โ†’ O(n).
  • DP patterns: Linear, Grid, Interval, Tree, Bitmask โ€” covering 90% of competitive programming DP problems.
Section M

Earning Checkpoint

Skill LearnedTool/MethodPortfolio OutputCan You Earn?
DP ConceptsTheoryโ€”โœ… Yes โ€” discuss confidently in interviews
Fibonacci/Stairs DPC++Solved problems on LeetCodeโœ… Yes โ€” basic interview ready
Coin ChangeC++GitHub repo with solutionsโœ… Yes โ€” ready for SDE interviews
House RobberC++Multiple variants solvedโœ… Yes โ€” medium-level interview ready
Min Cost Path (Grid DP)C++Grid DP solutions portfolioโœ… Yes โ€” covers grid DP pattern
DP TutoringTeachingSession recordings/testimonialsโœ… Yes โ€” โ‚น500โ€“โ‚น1,500/hour
Problem Set CreationDocumentationCurated problem setsโœ… Yes โ€” โ‚น5,000โ€“โ‚น15,000/set
Minimum Viable Earning Setup after this chapter: A LeetCode profile with 50+ DP problems solved + a Topmate profile offering interview coaching = you can earn โ‚น10,000โ€“โ‚น40,000/month from DP tutoring while still in college.

โœ… Unit 4 complete. Ready for Unit 5: Advanced DP Techniques!

[QR: Link to EduArtha video tutorial โ€” Basic Dynamic Programming]