Competitive Coding

Unit 5: Dynamic Programming Problems

Master the seven classic DP problems โ€” from Binomial Coefficients to Balanced Partitions โ€” with complete recurrences, table traces, C++/Python code, and optimization techniques used at top tech companies.

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

๐Ÿ’ผ Jobs this unlocks: SDE at FAANG (โ‚น25โ€“60 LPA)  |  Competitive Programmer (โ‚น15โ€“40 LPA)  |  Algorithm Engineer (โ‚น20โ€“50 LPA)

Section A

Opening Hook โ€” DP Powers the Products You Use Daily

๐Ÿ“ฆ How Flipkart's Warehouse Optimizer Packs Maximum Items

Every time you order from Flipkart during the Big Billion Days sale, a warehouse robot needs to decide how to stack boxes of different sizes into delivery trucks to maximise the number of items shipped per trip. This isn't trial-and-error โ€” it's the Box Stacking Problem, a classic Dynamic Programming challenge. Flipkart's logistics engine uses a variant of DP-based stacking to reduce shipping costs by 18% โ€” saving โ‚น200+ crores annually.

Meanwhile, when Netflix recommends your next binge-watch, it computes the Longest Common Subsequence (LCS) between your watch history and millions of other users. If you watched Breaking Bad โ†’ Narcos โ†’ Money Heist, and another user watched Breaking Bad โ†’ Peaky Blinders โ†’ Narcos โ†’ Money Heist โ†’ Ozark, the LCS is [Breaking Bad, Narcos, Money Heist] โ€” and Netflix recommends Peaky Blinders and Ozark to you. That's DP in production at scale.

What if YOU could build these algorithms? In this unit, you'll master 7 classic DP problems that appear in 60%+ of FAANG interviews. These same algorithms power spell-checkers (Edit Distance), DNA analysis (LCS), investment portfolios (Knapsack), and compiler optimizers (LIS).

๐Ÿ›’ Flipkart๐ŸŽฌ Netflix๐Ÿ” Google๐Ÿ“ฆ Amazon๐Ÿงฌ NCBI๐Ÿ’ณ Razorpay
Dynamic Programming was invented by Richard Bellman in the 1950s. He chose the name "Dynamic Programming" to hide the mathematical nature of his work from a US Secretary of Defense who hated the word "research." The word "dynamic" was chosen because it sounded impressive and couldn't be used pejoratively. Today, DP appears in 40%+ of coding interview problems at Google, Amazon, and Microsoft.
Section B

Learning Outcomes โ€” Bloom's Taxonomy Mapped (12 Outcomes)

Bloom's LevelLearning Outcome
๐Ÿ”ต RememberLO1: State the recurrence relations for Binomial Coefficient, 0/1 Knapsack, LIS, LCS, and Edit Distance
๐Ÿ”ต RememberLO2: List the base cases and boundary conditions for each of the 7 DP problems
๐ŸŸข UnderstandLO3: Explain the principle of optimal substructure and overlapping subproblems using the Knapsack problem as an example
๐ŸŸข UnderstandLO4: Describe how the Box Stacking problem reduces to a variant of Longest Increasing Subsequence
๐ŸŸก ApplyLO5: Trace and fill complete DP tables for Edit Distance, LCS, and Knapsack given specific inputs
๐ŸŸก ApplyLO6: Implement all 7 DP problems in C++ and Python with correct time and space complexity
๐ŸŸ  AnalyzeLO7: Compare the O(nยฒ) and O(n log n) approaches for LIS and determine when each is appropriate
๐ŸŸ  AnalyzeLO8: Analyze how space optimization reduces 2D DP tables to 1D arrays in Knapsack and Binomial Coefficient
๐Ÿ”ด EvaluateLO9: Evaluate whether a given problem has DP structure (optimal substructure + overlapping subproblems) vs. greedy structure
๐Ÿ”ด EvaluateLO10: Assess the trade-offs between top-down memoization and bottom-up tabulation approaches
๐ŸŸฃ CreateLO11: Design a DP solution for a novel problem by identifying states, transitions, and base cases
๐ŸŸฃ CreateLO12: Construct backtracking logic to reconstruct the actual solution (not just optimal value) for LCS and Edit Distance
Section C

Concept Explanation โ€” 7 Classic DP Problems

Each problem follows the standard DP methodology: Problem Statement โ†’ Intuition โ†’ Recurrence โ†’ DP Table Trace โ†’ Code (C++/Python) โ†’ Complexity โ†’ Optimization. Master this framework and you can solve any new DP problem.

The DP Thinking Framework: For every DP problem, ask these 4 questions: (1) What are the states? (2) What are the transitions (recurrence)? (3) What are the base cases? (4) What is the answer in terms of states? Answer these, and the code writes itself.

1. Binomial Coefficient C(n, k)

๐Ÿ“ Problem Statement

Compute the Binomial Coefficient C(n, k) = number of ways to choose k items from n items. Also written as โฟCโ‚– or "n choose k".

Example: C(5, 2) = 10 (there are 10 ways to choose 2 items from 5).

Intuition โ€” Pascal's Triangle

Every entry in Pascal's triangle is the sum of the two entries directly above it. The value at row n, position k is exactly C(n, k). Instead of computing factorials (which overflow for large n), we build the triangle row by row.

Recurrence Relation

Recurrence
// Pascal's Rule:
C(n, k) = C(n-1, k-1) + C(n-1, k)

// Base cases:
C(n, 0) = 1        // choosing 0 items = 1 way (empty set)
C(n, n) = 1        // choosing all items = 1 way

DP Table Trace โ€” C(5, 2)

n\k012345
01
111
2121
31331
414641
515101051

Answer: C(5, 2) = 10 โœ…

Code โ€” C++

C++
int binomialCoeff(int n, int k) {
    vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));
    for (int i = 0; i <= n; i++) {
        dp[i][0] = 1;  // C(i, 0) = 1
        for (int j = 1; j <= min(i, k); j++) {
            if (j == i)
                dp[i][j] = 1;  // C(i, i) = 1
            else
                dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
        }
    }
    return dp[n][k];
}

Code โ€” Python

Python
def binomial_coeff(n, k):
    dp = [[0] * (k + 1) for _ in range(n + 1)]
    for i in range(n + 1):
        dp[i][0] = 1
        for j in range(1, min(i, k) + 1):
            if j == i:
                dp[i][j] = 1
            else:
                dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
    return dp[n][k]

print(binomial_coeff(5, 2))  # Output: 10

Complexity

MetricValue
Time ComplexityO(n ร— k)
Space Complexity (naive)O(n ร— k)
Space OptimizedO(k) โ€” use 1D array, update right to left

Space Optimization โ€” O(k)

C++
int binomialOptimized(int n, int k) {
    vector<int> dp(k + 1, 0);
    dp[0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = min(i, k); j > 0; j--)  // right to left!
            dp[j] = dp[j] + dp[j - 1];
    return dp[k];
}
Why iterate right to left in space optimization? If we go left to right, dp[j-1] would already be overwritten with the current row's value. Going right to left ensures we use the previous row's values. This pattern appears in Knapsack too!

2. Box Stacking Problem

๐Ÿ“ฆ Problem Statement

Given n types of boxes, each with dimensions (height h, width w, depth d). You can rotate boxes so any side faces up. You can use multiple instances of each type. A box can be placed on top of another only if both its base dimensions are strictly smaller. Find the maximum height of the tallest stack.

Example: Boxes = {(4,6,7), (1,2,3), (4,5,6)}. After generating all rotations and sorting, find max stack height.

Intuition โ€” Reduce to LIS Variant

For each box, generate all 3 rotations (each face as base). Sort all rotations by base area (decreasing). Now the problem becomes: find the longest increasing subsequence of heights where each box's base dimensions are strictly smaller than the one below it โ€” a variant of LIS!

Algorithm Steps

  1. Generate rotations: For box (h, w, d), create 3 rotations where each dimension is the height and the base is (max of remaining, min of remaining)
  2. Sort by base area in decreasing order
  3. Apply LIS-like DP: dp[i] = max stack height with box i on top

Recurrence

Recurrence
// For each box i (sorted by base area descending):
dp[i] = height[i]   // base case: just box i alone

// For all j < i where box j's base fits strictly inside box i's base:
dp[i] = max(dp[i], dp[j] + height[i])
    where width[j] < width[i] AND depth[j] < depth[i]

Answer = max(dp[0], dp[1], ..., dp[n-1])

Trace Example

Given boxes: (4,6,7), (1,2,3), (4,5,6)

All rotations (h, w, d where w โ‰ฅ d):

#hwdBase Area
047642
167428
276424
346530
456424
565420
61326
72313
83212

After sorting by base area (descending) and running DP: Maximum height = 22

Code โ€” C++

C++
#include <bits/stdc++.h>
using namespace std;

struct Box { int h, w, d; };

bool cmp(Box &a, Box &b) {
    return (a.w * a.d) > (b.w * b.d);
}

int maxStackHeight(int height[], int width[], int depth[], int n) {
    vector<Box> rot;
    for (int i = 0; i < n; i++) {
        int dims[] = {height[i], width[i], depth[i]};
        sort(dims, dims+3);
        // 3 rotations: each dimension as height
        rot.push_back({dims[0], max(dims[1],dims[2]), min(dims[1],dims[2])});
        rot.push_back({dims[1], max(dims[0],dims[2]), min(dims[0],dims[2])});
        rot.push_back({dims[2], max(dims[0],dims[1]), min(dims[0],dims[1])});
    }
    sort(rot.begin(), rot.end(), cmp);

    int m = rot.size();
    vector<int> dp(m);
    for (int i = 0; i < m; i++) dp[i] = rot[i].h;

    for (int i = 1; i < m; i++)
        for (int j = 0; j < i; j++)
            if (rot[i].w < rot[j].w && rot[i].d < rot[j].d)
                dp[i] = max(dp[i], dp[j] + rot[i].h);

    return *max_element(dp.begin(), dp.end());
}

Code โ€” Python

Python
def max_stack_height(boxes):
    rotations = []
    for h, w, d in boxes:
        dims = sorted([h, w, d])
        rotations.append((dims[0], max(dims[1],dims[2]), min(dims[1],dims[2])))
        rotations.append((dims[1], max(dims[0],dims[2]), min(dims[0],dims[2])))
        rotations.append((dims[2], max(dims[0],dims[1]), min(dims[0],dims[1])))

    rotations.sort(key=lambda x: x[1] * x[2], reverse=True)
    n = len(rotations)
    dp = [r[0] for r in rotations]

    for i in range(1, n):
        for j in range(i):
            if rotations[i][1] < rotations[j][1] and \
               rotations[i][2] < rotations[j][2]:
                dp[i] = max(dp[i], dp[j] + rotations[i][0])

    return max(dp)

print(max_stack_height([(4,6,7), (1,2,3), (4,5,6)]))  # Output: 22

Complexity

MetricValue
TimeO(nยฒ ร— 9) = O(nยฒ) where n = number of box types (3n rotations)
SpaceO(n)

3. Integer Knapsack (0/1, Duplicate Items Forbidden)

๐ŸŽ’ Problem Statement โ€” The CLASSIC DP Problem

Given n items, each with a weight w[i] and value v[i], and a knapsack with capacity W. Find the maximum total value of items that fit in the knapsack. Each item can be used at most once.

Example: Items = {(wt=1, val=1), (wt=3, val=4), (wt=4, val=5), (wt=5, val=7)}, Capacity W = 7.

Indian analogy: Packing for a train journey. You have a bag that can hold only 7 kg. You have a water bottle (1 kg, value 1), a thali box (3 kg, value 4), a laptop (4 kg, value 5), and a blanket (5 kg, value 7). You can't take duplicates. What combination gives you the maximum comfort (value) for your Rajdhani Express journey?

Recurrence Relation

Recurrence
dp[i][w] = maximum value using first i items with capacity w

// Choice: include item i or exclude it
dp[i][w] = max(
    dp[i-1][w],                      // don't take item i
    dp[i-1][w - wt[i]] + val[i]      // take item i (if wt[i] โ‰ค w)
)

// Base cases:
dp[0][w] = 0   // 0 items โ†’ 0 value
dp[i][0] = 0   // 0 capacity โ†’ 0 value

Full DP Table Trace โ€” 4 Items, W = 7

Items: (1,1), (3,4), (4,5), (5,7) โ€” (weight, value)

Item\W01234567
0 (none)00000000
1 (1,1)01111111
2 (3,4)01145555
3 (4,5)01145669
4 (5,7)01145789

Answer: dp[4][7] = 9 (take items 2 and 3: weight 3+4=7, value 4+5=9) โœ…

Trace Walkthrough

Reading dp[4][7]=9: Can we include item 4 (wt=5, val=7)? dp[3][7-5]+7 = dp[3][2]+7 = 1+7 = 8. Don't include: dp[3][7]=9. So 9 > 8 โ†’ don't take item 4. Move to dp[3][7]=9. Include item 3 (wt=4, val=5)? dp[2][7-4]+5 = dp[2][3]+5 = 4+5 = 9 โœ…. Take item 3. Move to dp[2][3]=4. Include item 2 (wt=3, val=4)? dp[1][0]+4 = 0+4 = 4 โœ…. Take item 2. Done โ†’ Items {2, 3}.

Code โ€” C++

C++
int knapsack(int W, int wt[], int val[], int n) {
    vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));
    for (int i = 1; i <= n; i++) {
        for (int w = 0; w <= W; w++) {
            dp[i][w] = dp[i-1][w];  // don't take item i
            if (wt[i-1] <= w)
                dp[i][w] = max(dp[i][w], dp[i-1][w - wt[i-1]] + val[i-1]);
        }
    }
    return dp[n][W];
}

Code โ€” Python

Python
def knapsack(W, wt, val, n):
    dp = [[0] * (W + 1) for _ in range(n + 1)]
    for i in range(1, n + 1):
        for w in range(W + 1):
            dp[i][w] = dp[i-1][w]
            if wt[i-1] <= w:
                dp[i][w] = max(dp[i][w], dp[i-1][w - wt[i-1]] + val[i-1])
    return dp[n][W]

print(knapsack(7, [1,3,4,5], [1,4,5,7], 4))  # Output: 9

Space Optimization โ€” 1D Array

C++
int knapsack1D(int W, int wt[], int val[], int n) {
    vector<int> dp(W + 1, 0);
    for (int i = 0; i < n; i++)
        for (int w = W; w >= wt[i]; w--)  // RIGHT TO LEFT!
            dp[w] = max(dp[w], dp[w - wt[i]] + val[i]);
    return dp[W];
}
In 1D Knapsack, you MUST iterate weights right to left. If you go left to right, the same item can be picked multiple times (that's the Unbounded Knapsack, a different problem). Right-to-left ensures each item is considered only once.

Complexity

Metric2D Version1D Optimized
TimeO(n ร— W)O(n ร— W)
SpaceO(n ร— W)O(W)

4. Edit Distance (Levenshtein Distance)

โœ๏ธ Problem Statement

Given two strings A and B, find the minimum number of operations to transform A into B. Allowed operations: Insert, Delete, Replace โ€” each costs 1.

Example: Transform "saturday" โ†’ "sunday". Minimum operations = 3.

Applications: Spell checkers (Google "Did you mean?"), DNA sequence alignment, plagiarism detection, auto-correct on keyboards.

Recurrence Relation

Recurrence
dp[i][j] = min edits to convert A[0..i-1] to B[0..j-1]

if A[i-1] == B[j-1]:
    dp[i][j] = dp[i-1][j-1]           // characters match, no operation
else:
    dp[i][j] = 1 + min(
        dp[i-1][j],      // DELETE from A
        dp[i][j-1],      // INSERT into A
        dp[i-1][j-1]     // REPLACE in A
    )

// Base cases:
dp[i][0] = i    // delete all i chars from A
dp[0][j] = j    // insert all j chars into empty A

Full DP Table Trace โ€” "saturday" โ†’ "sunday"

""sunday
""0123456
s1012345
a2112334
t3222344
u4323345
r5433445
d6544345
a7655434
y8766543

Answer: Edit Distance = 3 (delete 'a', delete 't', replace 'r'โ†’'n') โœ…

Code โ€” C++

C++
int editDistance(string A, string B) {
    int m = A.size(), n = B.size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1));
    for (int i = 0; i <= m; i++) dp[i][0] = i;
    for (int j = 0; j <= n; j++) dp[0][j] = j;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (A[i-1] == B[j-1])
                dp[i][j] = dp[i-1][j-1];
            else
                dp[i][j] = 1 + min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]});
        }
    }
    return dp[m][n];
}

Code โ€” Python

Python
def edit_distance(A, B):
    m, n = len(A), len(B)
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    for i in range(m + 1): dp[i][0] = i
    for j in range(n + 1): dp[0][j] = j
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if A[i-1] == B[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
    return dp[m][n]

print(edit_distance("saturday", "sunday"))  # Output: 3

Complexity

MetricValue
TimeO(m ร— n)
SpaceO(m ร— n) โ€” can be optimized to O(min(m, n)) using 2 rows
Google's "Did you mean?" uses a variant of Edit Distance. When you type "programing" in Google, it computes the edit distance to "programming" (distance = 1, just one insertion of 'm') and suggests the correction. This runs across millions of dictionary words in milliseconds using tries + DP.

5. Longest Increasing Subsequence (LIS)

๐Ÿ“ˆ Problem Statement

Given an array of n integers, find the length of the longest subsequence where each element is strictly greater than the previous one. Elements need not be contiguous.

Example: Array = [10, 22, 9, 33, 21, 50, 41, 60, 80]. LIS = [10, 22, 33, 50, 60, 80], length = 6.

Approach 1: O(nยฒ) DP

Recurrence
Recurrence
dp[i] = length of LIS ending at index i

dp[i] = 1 + max(dp[j]) for all j < i where arr[j] < arr[i]

// Base case:
dp[i] = 1 for all i  // every element is an LIS of length 1

Answer = max(dp[0], dp[1], ..., dp[n-1])
DP Table Trace

Array: [10, 22, 9, 33, 21, 50, 41, 60, 80]

Index012345678
arr[]10229332150416080
dp[]121324456

Trace for dp[5]=4: arr[5]=50. Check j=0: 10<50 โ†’ dp[0]+1=2. j=1: 22<50 โ†’ dp[1]+1=3. j=2: 9<50 โ†’ 2. j=3: 33<50 โ†’ dp[3]+1=4. j=4: 21<50 โ†’ 3. Best = 4.

Answer: max(dp) = 6 โœ…

Code โ€” O(nยฒ) C++

C++
int lis_n2(int arr[], int n) {
    vector<int> dp(n, 1);
    for (int i = 1; i < n; i++)
        for (int j = 0; j < i; j++)
            if (arr[j] < arr[i])
                dp[i] = max(dp[i], dp[j] + 1);
    return *max_element(dp.begin(), dp.end());
}

Approach 2: O(n log n) โ€” Patience Sorting with Binary Search

Intuition: Maintain an array tails[] where tails[i] = smallest tail element of all increasing subsequences of length i+1. For each new element, use binary search to find its position.

Code โ€” O(n log n) C++

C++
int lis_nlogn(int arr[], int n) {
    vector<int> tails;
    for (int i = 0; i < n; i++) {
        auto it = lower_bound(tails.begin(), tails.end(), arr[i]);
        if (it == tails.end())
            tails.push_back(arr[i]);  // extend longest subsequence
        else
            *it = arr[i];             // replace to keep smallest tail
    }
    return tails.size();
}

Code โ€” O(n log n) Python

Python
from bisect import bisect_left

def lis_nlogn(arr):
    tails = []
    for x in arr:
        pos = bisect_left(tails, x)
        if pos == len(tails):
            tails.append(x)
        else:
            tails[pos] = x
    return len(tails)

print(lis_nlogn([10,22,9,33,21,50,41,60,80]))  # Output: 6

Complexity Comparison

ApproachTimeSpaceWhen to Use
O(nยฒ) DPO(nยฒ)O(n)n โ‰ค 5000, need actual subsequence
O(n log n) Binary SearchO(n log n)O(n)n โ‰ค 10โถ, competitive programming

6. Longest Common Subsequence (LCS)

๐Ÿ”— Problem Statement

Given two strings X and Y, find the length of the longest subsequence common to both. A subsequence is obtained by deleting some (or zero) characters without changing order.

Example: X = "ABCBDAB", Y = "BDCAB". LCS = "BCAB", length = 4.

Recurrence Relation

Recurrence
dp[i][j] = LCS of X[0..i-1] and Y[0..j-1]

if X[i-1] == Y[j-1]:
    dp[i][j] = dp[i-1][j-1] + 1       // characters match
else:
    dp[i][j] = max(dp[i-1][j], dp[i][j-1])  // skip one char from either

// Base cases:
dp[0][j] = 0    // empty X
dp[i][0] = 0    // empty Y

Full DP Table Trace โ€” "ABCBDAB" and "BDCAB"

""BDCAB
""000000
A000011
B011111
C011222
B011222
D012222
A012233
B012234

Answer: LCS length = 4 โœ…

Backtracking to Find Actual Subsequence

Start at dp[7][5]=4. X[6]='B'==Y[4]='B' โ†’ take 'B', go to dp[6][4]. X[5]='A'==Y[3]='A' โ†’ take 'A', go to dp[5][3]. X[4]='D'โ‰ Y[2]='C', dp[4][3]>dp[5][2] โ†’ go left dp[5][2]. X[4]='D'==Y[1]='D' โ†’ wait, we're at (5,2). X[4]='D'==Y[1]='D' โ†’ take 'D', go to dp[4][1]. dp[3][1]=1, X[2]='C'โ‰ Y[0]='B', go up. dp[2][1]=1, X[1]='B'==Y[0]='B' โ†’ take 'B', go to dp[1][0]=0. Done.

LCS (reversed): B, D, A, B โ†’ "BDAB" (one of the valid LCS; "BCAB" is another)

Code โ€” C++

C++
int lcs(string X, string Y) {
    int m = X.size(), n = Y.size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++)
            if (X[i-1] == Y[j-1])
                dp[i][j] = dp[i-1][j-1] + 1;
            else
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
    return dp[m][n];
}

// Backtrack to find actual LCS:
string findLCS(string X, string Y, vector<vector<int>>& dp) {
    string result = "";
    int i = X.size(), j = Y.size();
    while (i > 0 && j > 0) {
        if (X[i-1] == Y[j-1]) {
            result = X[i-1] + result;
            i--; j--;
        } else if (dp[i-1][j] > dp[i][j-1])
            i--;
        else
            j--;
    }
    return result;
}

Code โ€” Python

Python
def lcs(X, Y):
    m, n = len(X), len(Y)
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if X[i-1] == Y[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]

print(lcs("ABCBDAB", "BDCAB"))  # Output: 4

Complexity

MetricValue
TimeO(m ร— n)
SpaceO(m ร— n) โ€” can optimize to O(min(m,n))

7. Balanced Partition Problem

โš–๏ธ Problem Statement

Given an array of positive integers, partition it into two subsets such that the difference of their sums is minimized.

Example: Array = [1, 6, 11, 5]. Total = 23. Best partition: {1, 5, 6} (sum=12) and {11} (sum=11). Minimum difference = 1.

Reduction to Subset Sum

If total sum = S, we want to find a subset with sum as close to S/2 as possible. If we find the largest achievable sum โ‰ค S/2, call it maxSum, then minimum difference = S โˆ’ 2 ร— maxSum. This reduces to the Subset Sum problem.

Recurrence

Recurrence
dp[i][j] = true if a subset of first i elements can sum to j

dp[i][j] = dp[i-1][j]              // don't include arr[i-1]
         OR dp[i-1][j - arr[i-1]]  // include arr[i-1]

// Base cases:
dp[i][0] = true   // empty subset sums to 0
dp[0][j] = false  // no elements, can't make non-zero sum

Answer: Find largest j โ‰ค S/2 where dp[n][j] == true
        Min difference = S - 2*j

Code โ€” C++

C++
int balancedPartition(int arr[], int n) {
    int S = 0;
    for (int i = 0; i < n; i++) S += arr[i];

    vector<vector<bool>> dp(n + 1, vector<bool>(S / 2 + 1, false));
    for (int i = 0; i <= n; i++) dp[i][0] = true;

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= S / 2; j++) {
            dp[i][j] = dp[i-1][j];
            if (arr[i-1] <= j)
                dp[i][j] = dp[i][j] || dp[i-1][j - arr[i-1]];
        }

    for (int j = S / 2; j >= 0; j--)
        if (dp[n][j]) return S - 2 * j;
    return S;
}

Code โ€” Python

Python
def balanced_partition(arr):
    S = sum(arr)
    n = len(arr)
    half = S // 2
    dp = [[False] * (half + 1) for _ in range(n + 1)]
    for i in range(n + 1): dp[i][0] = True

    for i in range(1, n + 1):
        for j in range(1, half + 1):
            dp[i][j] = dp[i-1][j]
            if arr[i-1] <= j:
                dp[i][j] = dp[i][j] or dp[i-1][j - arr[i-1]]

    for j in range(half, -1, -1):
        if dp[n][j]:
            return S - 2 * j

print(balanced_partition([1, 6, 11, 5]))  # Output: 1

Complexity

MetricValue
TimeO(n ร— S/2)
SpaceO(n ร— S/2) โ€” can optimize to O(S/2) with 1D array
Balanced Partition is essentially 0/1 Knapsack with capacity = S/2. If you master Knapsack, you've already mastered this problem. Many DP problems are disguised versions of each other โ€” recognizing the pattern is the real skill.
Section D

Learn by Doing โ€” 3-Tier Lab Structure

๐ŸŸข Tier 1 โ€” GUIDED: Longest Increasing Subsequence (LIS)

โฑ๏ธ 45โ€“60 minutesBeginnerStep-by-step guidance

Step 1: Understand the Input

Array: [3, 10, 2, 1, 20]. Expected LIS length = 3 (e.g., [3, 10, 20]).

Step 2: Initialize DP Array

Create dp[5] = {1, 1, 1, 1, 1} โ€” every element is an LIS of length 1 by itself.

Step 3: Fill the DP Table

i=1 (arr[1]=10): j=0: arr[0]=3 < 10 โ†’ dp[1] = max(1, dp[0]+1) = 2.
i=2 (arr[2]=2): j=0: 3>2 skip. j=1: 10>2 skip. dp[2]=1.
i=3 (arr[3]=1): All previous โ‰ฅ 1. dp[3]=1.
i=4 (arr[4]=20): j=0: 3<20 โ†’ dp[4]=max(1,2)=2. j=1: 10<20 โ†’ max(2,3)=3. j=2: 2<20 โ†’ max(3,2)=3. j=3: 1<20 โ†’ max(3,2)=3. dp[4]=3.

Step 4: Code It

Python
def lis(arr):
    n = len(arr)
    dp = [1] * n
    for i in range(1, n):
        for j in range(i):
            if arr[j] < arr[i]:
                dp[i] = max(dp[i], dp[j] + 1)
    return max(dp)

print(lis([3, 10, 2, 1, 20]))  # Output: 3

Step 5: Test with More Inputs

Try: [50, 3, 10, 7, 40, 80] โ†’ Expected: 4 ([3, 10, 40, 80])

Try: [5, 4, 3, 2, 1] โ†’ Expected: 1 (decreasing array)

๐ŸŸก Tier 2 โ€” SEMI-GUIDED: 0/1 Knapsack Problem

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

Your Mission:

Implement the 0/1 Knapsack for: Items = [(2,3), (3,4), (4,5), (5,6)], Capacity = 8. Find max value.

Hints:

  1. Create a 2D DP table of size (n+1) ร— (W+1), initialized to 0
  2. For each item i and weight w, decide: include or exclude?
  3. If wt[i] > w, you can't include โ†’ dp[i][w] = dp[i-1][w]
  4. Otherwise, take max of including vs excluding
  5. After filling the table, backtrack to find which items were selected
Stretch Goal: Implement the space-optimized 1D version. Remember: iterate weights from W down to wt[i] (right to left). Verify your answers match the 2D version.

๐Ÿ”ด Tier 3 โ€” OPEN CHALLENGE: Edit Distance with Backtracking

โฑ๏ธ 2โ€“3 hoursAdvancedNo instructions โ€” real interview question

The Challenge:

  1. Implement Edit Distance for any two strings
  2. After computing the DP table, backtrack to print the exact sequence of operations (Insert/Delete/Replace)
  3. Handle edge cases: empty strings, identical strings, single character strings
  4. Optimize space to O(min(m,n)) using 2 rows
  5. Test with: "intention" โ†’ "execution" (expected: 5)
Interview Extension: Amazon asks: "Given a dictionary of 10,000 words, find the top-5 closest words to a misspelled input using Edit Distance." Implement this using your Edit Distance function + a priority queue.
Section E

Problem Set โ€” Tracing, Programming & Interview Problems

Part 1: DP Table Tracing (5 Problems)

T1. Fill the complete DP table for LCS of X="AGGTAB" and Y="GXTXAYB". What is the LCS length?

T2. Trace the 0/1 Knapsack DP table for items [(1,1), (2,6), (3,10), (5,15), (7,16)] with W=8. Which items are selected?

T3. Fill the Edit Distance DP table for "kitten" โ†’ "sitting". Show all 7ร—8 = 56 cells.

T4. Trace the LIS dp[] array for [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]. What is the LIS length?

T5. Fill the Binomial Coefficient table (Pascal's Triangle) for n=8, and find C(8,3) and C(8,5). Verify C(8,3) = C(8,5).

Part 2: Programming Problems (8 Problems)

P1. Beginner Implement LIS with O(nยฒ) DP. Input: array of integers. Output: LIS length.

P2. Beginner Implement LCS for two strings. Print both the length and the actual subsequence.

P3. Intermediate Implement 0/1 Knapsack with backtracking to print selected items.

P4. Intermediate Implement Edit Distance and print the sequence of operations to transform A to B.

P5. Intermediate Implement Box Stacking. Handle all 3 rotations correctly. Print the stack order.

P6. Intermediate Implement Balanced Partition and print both subsets.

P7. Advanced Implement LIS in O(n log n) using binary search. Reconstruct the actual subsequence (not just length).

P8. Advanced Given a grid of mร—n with positive integers, find the path from top-left to bottom-right with minimum sum (move only right or down). Use DP.

Part 3: Industry Application Problems (3 Problems)

๐Ÿญ I1. Flipkart Delivery Optimization

A delivery truck has capacity 500 kg. There are 20 packages with given weights and "priority scores" (value). Use 0/1 Knapsack to select packages that maximize total priority within the weight limit. Implement and test with realistic data.

๐Ÿงฌ I2. DNA Sequence Alignment

Given two DNA sequences (strings of A, C, G, T), use LCS to find the longest matching subsequence. Then use Edit Distance to compute the mutation distance. Compare results for: "ACGTACGT" and "ACGTAGCT".

๐Ÿ“ I3. Auto-Correct System

Given a dictionary of 100 common English words, build a spell-checker. For any misspelled input, output the 3 closest words by Edit Distance. Handle tie-breaking alphabetically.

Part 4: Interview Questions (3 Problems)

๐Ÿ’ผ Asked at Amazon โ€” Coin Change Problem

Given coins of denominations [1, 5, 10, 25] and a target amount, find the minimum number of coins needed. This is unbounded knapsack variant. Follow-up: What if you also need to print which coins were used?

๐Ÿ’ผ Asked at Google โ€” Longest Palindromic Subsequence

Given a string, find the length of its longest palindromic subsequence. Hint: This is LCS of the string with its reverse. Example: "BBABCBCAB" โ†’ LPS = "BABCBAB", length = 7.

๐Ÿ’ผ Asked at Microsoft โ€” Wildcard Pattern Matching

Given a string and a pattern with '?' (matches single char) and '*' (matches any sequence), determine if the pattern matches the string. Use DP. Example: "adceb" matches "*a*b" โ†’ true. "acdcb" matches "a*c?b" โ†’ false.

Section F

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

Remember / Identify (Q1โ€“Q5)

Q1

What are the two key properties required for a problem to be solvable by Dynamic Programming?

  1. Greedy choice and optimal substructure
  2. Optimal substructure and overlapping subproblems
  3. Divide and conquer and memoization
  4. Recursion and iteration
Remember
โœ… Answer: (B) โ€” DP requires both optimal substructure (optimal solution contains optimal solutions to subproblems) and overlapping subproblems (same subproblems are solved repeatedly).
Q2

The recurrence for Binomial Coefficient C(n, k) using Pascal's Triangle is:

  1. C(n,k) = C(n-1,k-1) ร— C(n-1,k)
  2. C(n,k) = C(n-1,k-1) + C(n-1,k)
  3. C(n,k) = C(n,k-1) + C(n-1,k)
  4. C(n,k) = n! / (k! ร— (n-k)!)
Remember
โœ… Answer: (B) โ€” Pascal's Rule: each entry is the sum of the two entries above it. While (D) is mathematically correct, (B) is the DP recurrence.
Q3

In the 0/1 Knapsack problem, what does "0/1" signify?

  1. Items have binary weights (0 or 1)
  2. Each item can be taken at most once (either 0 or 1 times)
  3. The knapsack has only 0 or 1 capacity
  4. There are only 2 items to choose from
Remember
โœ… Answer: (B) โ€” "0/1" means each item is either included (1) or excluded (0). No partial items, no duplicates.
Q4

The three operations allowed in Edit Distance are:

  1. Insert, Delete, Swap
  2. Insert, Delete, Replace
  3. Add, Remove, Modify
  4. Push, Pop, Replace
Remember
โœ… Answer: (B) โ€” The three operations in Levenshtein distance are Insert (a character into A), Delete (a character from A), and Replace (a character in A).
Q5

What is the base case for LIS (dp[i])?

  1. dp[i] = 0 for all i
  2. dp[i] = 1 for all i
  3. dp[0] = 1, rest are 0
  4. dp[i] = arr[i] for all i
Remember
โœ… Answer: (B) โ€” Every single element is an increasing subsequence of length 1 by itself.

Understand / Explain (Q6โ€“Q10)

Q6

Why can't we use a greedy approach for the 0/1 Knapsack problem?

  1. Greedy is always slower than DP
  2. Taking the item with best value/weight ratio doesn't guarantee optimal solution when items can't be split
  3. Greedy can't handle arrays
  4. 0/1 Knapsack has no optimal substructure
Understand
โœ… Answer: (B) โ€” In fractional knapsack, greedy works because you can take fractions. In 0/1 knapsack, taking the "best ratio" item might prevent you from fitting a better overall combination.
Q7

In the LCS recurrence, when X[i-1] โ‰  Y[j-1], why do we take max(dp[i-1][j], dp[i][j-1])?

  1. We delete both characters
  2. We try skipping one character from either string and take the better result
  3. We replace one character
  4. We insert a character
Understand
โœ… Answer: (B) โ€” When characters don't match, we either skip the current char of X (dp[i-1][j]) or skip the current char of Y (dp[i][j-1]), whichever gives a longer common subsequence.
Q8

Why does the Box Stacking problem reduce to LIS?

  1. Both problems have the same time complexity
  2. Both use 1D DP arrays
  3. After sorting by base area and generating rotations, finding max stack is like finding longest increasing chain of compatible boxes
  4. LIS is always used for stacking problems
Understand
โœ… Answer: (C) โ€” After sorting boxes by base area (decreasing), we need to find the longest chain where each box's base fits strictly inside the one below โ€” structurally identical to finding an increasing sequence.
Q9

What does the cell dp[i][j] represent in the Edit Distance table?

  1. The number of common characters between A[0..i] and B[0..j]
  2. The minimum operations to convert A[0..i-1] to B[0..j-1]
  3. The maximum operations needed
  4. The edit distance of the remaining characters
Understand
โœ… Answer: (B) โ€” dp[i][j] = minimum number of insert/delete/replace operations to transform the first i characters of A into the first j characters of B.
Q10

In the Balanced Partition problem, why do we only need to find subset sum up to S/2?

  1. No subset can have sum greater than S/2
  2. If one subset has sum โ‰ค S/2 and is as close to S/2 as possible, it minimizes the difference with the other subset
  3. We always split arrays in half
  4. S/2 is the average element value
Understand
โœ… Answer: (B) โ€” If subset1 sum = x, then subset2 sum = S-x. Difference = |S-2x|. To minimize this, we maximize x subject to x โ‰ค S/2.

Apply / Compute (Q11โ€“Q15)

Q11

What is C(6, 2) using Pascal's Triangle?

  1. 12
  2. 15
  3. 20
  4. 30
Apply
โœ… Answer: (B) 15 โ€” C(6,2) = C(5,1)+C(5,2) = 5+10 = 15. Alternatively, 6!/(2!ร—4!) = 720/(2ร—24) = 15.
Q12

For arr = [5, 1, 4, 2, 8], what is the LIS length?

  1. 2
  2. 3
  3. 4
  4. 5
Apply
โœ… Answer: (B) 3 โ€” LIS is [1, 4, 8] or [1, 2, 8], both of length 3.
Q13

What is the Edit Distance between "cat" and "cut"?

  1. 0
  2. 1
  3. 2
  4. 3
Apply
โœ… Answer: (B) 1 โ€” Replace 'a' with 'u'. Only 1 operation needed.
Q14

For Knapsack with items [(wt=2, val=3), (wt=3, val=4)] and capacity W=4, what is the max value?

  1. 3
  2. 4
  3. 7
  4. 0
Apply
โœ… Answer: (A) 3 โ€” Item 1 (wt=2, val=3) fits. Item 2 (wt=3, val=4) fits. But both together need wt=5 > 4. Best: take item 2 (val=4). Wait โ€” item 2 has val=4 and wt=3 โ‰ค 4, so max is 4. Actually answer is (B) 4.
Q15

What is the LCS length of "ABC" and "AC"?

  1. 1
  2. 2
  3. 3
  4. 0
Apply
โœ… Answer: (B) 2 โ€” LCS is "AC" (characters A and C appear in both strings in the same order).

Analyze / Compare (Q16โ€“Q20)

Q16

What is the key advantage of the O(n log n) LIS algorithm over the O(nยฒ) approach?

  1. It uses less memory
  2. It handles negative numbers
  3. It scales to arrays of size 10โถ+ where O(nยฒ) would TLE
  4. It's easier to implement
Analyze
โœ… Answer: (C) โ€” For n=10โถ, O(nยฒ) = 10ยนยฒ operations (too slow). O(n log n) = ~20ร—10โถ operations (fast enough). This is critical in competitive programming.
Q17

In 1D Knapsack space optimization, why must we iterate weights from W down to wt[i]?

  1. It's faster than left to right
  2. To avoid using the same item multiple times in the same row
  3. The compiler optimizes it better
  4. The recurrence requires it mathematically
Analyze
โœ… Answer: (B) โ€” Left to right iteration would let dp[w-wt[i]] use the already-updated value from the same item's row, effectively allowing duplicates (unbounded knapsack).
Q18

Which DP problem has the same recurrence structure as Balanced Partition?

  1. LCS
  2. Edit Distance
  3. Subset Sum / 0/1 Knapsack
  4. LIS
Analyze
โœ… Answer: (C) โ€” Balanced Partition reduces directly to Subset Sum (find subset with sum closest to S/2), which is a special case of 0/1 Knapsack where value equals weight.
Q19

If we apply Edit Distance to strings of length m=1000 and n=1000, approximately how many operations are performed?

  1. 1,000
  2. 2,000
  3. 1,000,000
  4. 1,000,000,000
Analyze
โœ… Answer: (C) โ€” O(mร—n) = O(1000ร—1000) = 1,000,000. This runs in about 10ms on modern hardware.
Q20

Compare top-down (memoization) vs bottom-up (tabulation) DP. Which is true?

  1. Top-down is always faster
  2. Bottom-up avoids recursion overhead and stack overflow risks
  3. They always compute exactly the same set of subproblems
  4. Top-down cannot be space optimized
Analyze
โœ… Answer: (B) โ€” Bottom-up uses iteration (no recursion stack), avoids stack overflow for deep recursion, and is easier to space-optimize. Top-down may compute fewer subproblems if not all are needed.

Evaluate / Judge (Q21โ€“Q25)

Q21

A student claims: "The 0/1 Knapsack problem has O(nW) time complexity, so it's polynomial time." Is this correct?

  1. Yes, O(nW) is clearly polynomial
  2. No, it's pseudo-polynomial because W is exponential in the number of bits needed to represent it
  3. No, it's exponential
  4. Yes, because n and W are both linear
Evaluate
โœ… Answer: (B) โ€” O(nW) looks polynomial but W can be exponentially large relative to its input size (number of bits = log W). If W = 2^30, we need 10โน operations even for n=1. This makes Knapsack NP-hard.
Q22

A developer uses Edit Distance to compare 10-million-character DNA sequences. Is this approach practical?

  1. Yes, Edit Distance works for any size input
  2. No โ€” O(mร—n) = O(10ยนโด) operations would take years. Specialized bioinformatics algorithms (BLAST, Smith-Waterman) are needed.
  3. Yes, with memoization it will be fast enough
  4. No, Edit Distance only works for short strings
Evaluate
โœ… Answer: (B) โ€” For m=n=10โท, O(mร—n) = 10ยนโด operations is infeasible. Real DNA alignment uses heuristic algorithms like BLAST that sacrifice some optimality for speed.
Q23

Is it possible to reconstruct the actual LIS (not just its length) from the O(n log n) algorithm?

  1. No, the tails array doesn't store the actual subsequence
  2. Yes, by maintaining a parent/predecessor array alongside the tails array
  3. Only with the O(nยฒ) algorithm
  4. Yes, the tails array IS the LIS
Evaluate
โœ… Answer: (B) โ€” While the tails array doesn't directly give the LIS, we can maintain a predecessor array that tracks which element each position was updated from, allowing O(n log n) reconstruction. Note: (D) is wrong โ€” tails stores smallest tails, not the actual LIS.
Q24

Evaluate: "Balanced Partition always produces two subsets of equal size." True or False?

  1. True โ€” that's what "balanced" means
  2. False โ€” "balanced" refers to minimizing the sum difference, not the count of elements
  3. True โ€” it's required by the algorithm
  4. It depends on the array size
Evaluate
โœ… Answer: (B) โ€” "Balanced" means minimum difference in sums, not equal number of elements. [1,6,11,5] โ†’ {11} and {1,5,6} have different sizes but minimum sum difference of 1.
Q25

Is a greedy approach correct for Box Stacking? (Always pick the box with the largest base area first)

  1. Yes, larger base area always supports more weight
  2. No โ€” a box with a larger area might have a shorter height, and skipping it could allow stacking more boxes with greater total height
  3. Yes, greedy is optimal for any stacking problem
  4. It depends on the number of boxes
Evaluate
โœ… Answer: (B) โ€” Greedy fails because a locally optimal choice (largest base) might block a globally better combination. DP explores all valid stackings.

Create / Design (Q26โ€“Q30)

Q26

To find the Longest Palindromic Subsequence (LPS) of a string S, which DP strategy works?

  1. Apply LIS on the string's ASCII values
  2. Compute LCS of S and reverse(S)
  3. Use Edit Distance of S with reverse(S)
  4. Apply Knapsack with character weights
Create
โœ… Answer: (B) โ€” The LPS of S equals the LCS of S and its reverse. This elegant reduction shows how DP problems can be transformed into each other.
Q27

How would you modify 0/1 Knapsack to handle items with both weight AND volume constraints?

  1. Use a 2D Knapsack: dp[i][w][v] โ€” add a volume dimension
  2. Sum weight and volume into a single constraint
  3. Run Knapsack twice โ€” once for weight, once for volume
  4. It's impossible with DP
Create
โœ… Answer: (A) โ€” Extend the DP state to include both constraints: dp[i][w][v] = max value using first i items with weight โ‰ค w and volume โ‰ค v. Time: O(nร—Wร—V).
Q28

How would you use Edit Distance to implement an autocomplete feature?

  1. Compute Edit Distance of input prefix against all dictionary words and suggest the closest ones
  2. Use LCS instead of Edit Distance
  3. Use binary search on the dictionary
  4. Edit Distance can't be used for autocomplete
Create
โœ… Answer: (A) โ€” Compute Edit Distance between the user's (possibly misspelled) input and each word in the dictionary. Return the top-k words with smallest distance. Optimize with tries or BK-trees for large dictionaries.
Q29

To solve "Minimum number of coins to make change for amount N," which DP formulation is correct?

  1. dp[i] = min(dp[i-coin] + 1) for each coin denomination โ€” unbounded knapsack variant
  2. dp[i] = dp[i-1] + dp[i-2]
  3. Use LIS on coin denominations
  4. Use Edit Distance on coin values
Create
โœ… Answer: (A) โ€” For each amount i, try each coin c and take dp[i-c]+1. This is an unbounded knapsack variant where coins can be used unlimited times.
Q30

Design a DP solution for: "Given a rod of length n and prices for each length 1..n, maximize revenue by cutting the rod." What's the state?

  1. dp[i] = max revenue from rod of length i
  2. dp[i][j] = revenue from cutting at position i,j
  3. dp[i] = number of cuts for length i
  4. dp[i][j] = LCS of cuts
Create
โœ… Answer: (A) โ€” dp[i] = max revenue for rod of length i. Transition: dp[i] = max(price[j] + dp[i-j]) for j from 1 to i. This is an unbounded knapsack variant.
Section G

Short Answer Questions (8 Questions)

SA1. What are the two essential properties of Dynamic Programming? Explain each with a brief example.

Answer:

1. Optimal Substructure: An optimal solution to the problem contains optimal solutions to its subproblems. Example: In shortest path, if the shortest Aโ†’C path goes through B, then the Aโ†’B and Bโ†’C segments must also be shortest paths.

2. Overlapping Subproblems: The same subproblems are solved repeatedly. Example: In Fibonacci, fib(5) calls fib(4) and fib(3), but fib(4) also calls fib(3) โ€” fib(3) is computed twice. DP stores it once.

SA2. Write the recurrence relation for Edit Distance and explain each case.

Answer:

dp[i][j] = min edits to convert A[0..i-1] to B[0..j-1].

โ€ข If A[i-1] == B[j-1]: dp[i][j] = dp[i-1][j-1] โ€” characters match, no operation needed.

โ€ข Else: dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])

  - dp[i-1][j] + 1: Delete A[i-1]

  - dp[i][j-1] + 1: Insert B[j-1] into A

  - dp[i-1][j-1] + 1: Replace A[i-1] with B[j-1]

SA3. Explain how the Box Stacking problem reduces to LIS with an example.

Answer:

1. Generate all rotations of each box (3 per box, using each dimension as height). 2. Sort by base area (decreasing). 3. Now finding the tallest stack = finding a chain of boxes where each box's width AND depth are strictly smaller than the box below. This is exactly the LIS problem where the "increasing" condition is on two dimensions (width and depth) instead of one. The DP is dp[i] = max height ending at box i.

SA4. Differentiate between top-down memoization and bottom-up tabulation in DP.

Answer:

Top-down (Memoization): Start from the original problem, recursively break into subproblems, cache results. Uses recursion + hash map/array. May not solve all subproblems. Risk of stack overflow for deep recursion.

Bottom-up (Tabulation): Start from smallest subproblems, iteratively build up to the answer. Uses iteration + table. Solves all subproblems. No stack overflow risk. Easier to space-optimize.

SA5. Why is 0/1 Knapsack NP-hard despite having O(nW) time complexity?

Answer:

O(nW) is pseudo-polynomial, not truly polynomial. The input size is measured in bits: W requires logโ‚‚(W) bits to represent. If W = 2ยณโฐ (~10โน), the input size is only 30 bits, but O(nW) = O(n ร— 10โน) โ€” exponential in the input size. A truly polynomial algorithm would be O(n ร— polylog(W)), which is not known to exist for Knapsack.

SA6. Explain the space optimization technique for converting 2D DP to 1D in Knapsack.

Answer:

In 2D Knapsack, dp[i][w] only depends on row i-1. So we only need 2 rows, or even 1 row if we iterate weights right-to-left. When computing dp[w] for item i, the values dp[w-wt[i]] haven't been updated yet (still contain row i-1 values). This ensures each item is used at most once. Iterate from W down to wt[i] to preserve this invariant.

SA7. What is the time complexity of the O(n log n) LIS algorithm, and how does binary search help?

Answer:

The algorithm maintains a tails array where tails[i] = smallest tail element of all increasing subsequences of length i+1. For each new element, binary search (O(log n)) finds its position: either extend the array or replace an existing element. n elements ร— O(log n) each = O(n log n) total. The key insight: the tails array is always sorted, enabling binary search.

SA8. Name three real-world applications each for Edit Distance and LCS.

Answer:

Edit Distance: (1) Spell-checkers ("Did you mean?"), (2) DNA mutation analysis in bioinformatics, (3) Plagiarism detection in academic papers.

LCS: (1) Diff tools (git diff) for comparing file versions, (2) DNA/protein sequence alignment (NCBI BLAST), (3) Recommendation systems (Netflix: finding similar watch histories).

Section H

Long Answer Questions (3 Questions)

LA1. Explain the 0/1 Knapsack problem. Derive the recurrence, trace the DP table for items {(2,3), (3,4), (4,5), (5,6)} with W=5, and write C++ code. (12 marks)

Problem: Given n items with weights and values, maximize value within capacity W. Each item used at most once.

Recurrence: dp[i][w] = max(dp[i-1][w], dp[i-1][w-wt[i-1]] + val[i-1]) if wt[i-1] โ‰ค w, else dp[i][w] = dp[i-1][w].

Base cases: dp[0][w] = 0, dp[i][0] = 0.

DP Table:

i\w012345
0000000
1(2,3)003333
2(3,4)003447
3(4,5)003457
4(5,6)003457

Answer: 7 (items 1 and 2: weight 2+3=5, value 3+4=7)

C++ Code:

C++
int knapsack(int W, int wt[], int val[], int n) {
    int dp[n+1][W+1];
    memset(dp, 0, sizeof(dp));
    for(int i=1; i<=n; i++)
        for(int w=1; w<=W; w++) {
            dp[i][w] = dp[i-1][w];
            if(wt[i-1] <= w)
                dp[i][w] = max(dp[i][w],
                    dp[i-1][w-wt[i-1]] + val[i-1]);
        }
    return dp[n][W];
}

LA2. Explain the Longest Common Subsequence (LCS) problem. Derive the recurrence, trace the full DP table for X="AXYT" and Y="AYZX", perform backtracking to find the actual LCS, and analyze complexity. (12 marks)

Problem: Find the longest subsequence common to both strings.

Recurrence: If X[i-1]==Y[j-1]: dp[i][j] = dp[i-1][j-1]+1. Else: dp[i][j] = max(dp[i-1][j], dp[i][j-1]).

DP Table for "AXYT" vs "AYZX":

""AYZX
""00000
A01111
X01112
Y01222
T01222

LCS length = 2. Backtracking: dp[4][4]=2. Tโ‰ X, go up. dp[3][4]=2. Yโ‰ X, dp[2][4]โ‰ฅdp[3][3] โ†’ go up. dp[2][4]=2. X==X โ†’ take 'X', go to dp[1][3]=1. dp[1][3]=1. Aโ‰ Z, go left. dp[1][2]=1. Aโ‰ Y, go left. dp[1][1]=1. A==A โ†’ take 'A'. LCS = "AX".

Time complexity: O(mร—n). Space: O(mร—n), optimizable to O(min(m,n)).

LA3. Compare and contrast the following DP problems: LIS, LCS, and Edit Distance. For each, state the problem, recurrence, time complexity, and one real-world application. (12 marks)

AspectLISLCSEdit Distance
InputSingle arrayTwo stringsTwo strings
GoalLongest increasing subsequenceLongest common subsequenceMin operations to transform
DP Statedp[i] = LIS ending at idp[i][j] = LCS of prefixesdp[i][j] = min edits for prefixes
Dimension1D2D2D
TimeO(nยฒ) or O(n log n)O(mร—n)O(mร—n)
SpaceO(n)O(mร—n)O(mร—n)
ApplicationStock trading (longest price increase run)Git diff, DNA alignmentSpell checker, autocorrect

Key insight: LCS and Edit Distance are closely related. For strings of same length n: Edit Distance = n โˆ’ LCS length (when only insert/delete allowed). All three share the DP methodology: define states, establish transitions, fill table, extract answer.

Section I

Lab Programs โ€” Complete Code, Output & Viva Questions

Lab 1: Longest Increasing Subsequence (LIS)

๐Ÿ“˜ Syllabus Programโฑ๏ธ 30 min
C++
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cout << "Enter array size: ";
    cin >> n;
    vector<int> arr(n), dp(n, 1);
    cout << "Enter elements: ";
    for (int i = 0; i < n; i++) cin >> arr[i];

    for (int i = 1; i < n; i++)
        for (int j = 0; j < i; j++)
            if (arr[j] < arr[i])
                dp[i] = max(dp[i], dp[j] + 1);

    cout << "LIS Length: " << *max_element(dp.begin(), dp.end());
    return 0;
}
Enter array size: 9 Enter elements: 10 22 9 33 21 50 41 60 80 LIS Length: 6
Viva Questions
  1. Q: What is the time complexity of LIS using DP?
    A: O(nยฒ) โ€” two nested loops.
  2. Q: Can LIS be solved in better than O(nยฒ)?
    A: Yes, O(n log n) using patience sorting with binary search.
  3. Q: What is the space complexity?
    A: O(n) for the dp array.
  4. Q: Is the LIS unique?
    A: Not necessarily. Multiple subsequences can have the same maximum length.
  5. Q: How would you print the actual LIS, not just its length?
    A: Maintain a predecessor/parent array. After finding the max dp[i], backtrack using the parent array.

Lab 2: Longest Common Subsequence (LCS)

๐Ÿ“˜ Syllabus Programโฑ๏ธ 30 min
C++
#include <bits/stdc++.h>
using namespace std;

int main() {
    string X, Y;
    cout << "Enter string X: "; cin >> X;
    cout << "Enter string Y: "; cin >> Y;
    int m = X.size(), n = Y.size();
    vector<vector<int>> dp(m+1, vector<int>(n+1, 0));

    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++)
            if (X[i-1] == Y[j-1])
                dp[i][j] = dp[i-1][j-1] + 1;
            else
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);

    // Backtrack to find LCS string
    string lcs = "";
    int i = m, j = n;
    while (i > 0 && j > 0) {
        if (X[i-1] == Y[j-1]) { lcs = X[i-1] + lcs; i--; j--; }
        else if (dp[i-1][j] > dp[i][j-1]) i--;
        else j--;
    }

    cout << "LCS Length: " << dp[m][n] << endl;
    cout << "LCS: " << lcs << endl;
    return 0;
}
Enter string X: ABCBDAB Enter string Y: BDCAB LCS Length: 4 LCS: BDAB
Viva Questions
  1. Q: What's the difference between subsequence and substring?
    A: Subsequence = not necessarily contiguous. Substring = contiguous.
  2. Q: Time and space complexity?
    A: O(mร—n) time and space.
  3. Q: How is LCS related to diff tools?
    A: Git diff uses LCS to find unchanged lines between file versions.
  4. Q: Can LCS be used to find Longest Palindromic Subsequence?
    A: Yes! LPS(S) = LCS(S, reverse(S)).
  5. Q: How to optimize space?
    A: Use only 2 rows (current and previous), O(min(m,n)) space.

Lab 3: Binomial Coefficient C(n, k)

๐Ÿ“˜ Syllabus Programโฑ๏ธ 20 min
Python
def binomial(n, k):
    dp = [0] * (k + 1)
    dp[0] = 1
    for i in range(1, n + 1):
        for j in range(min(i, k), 0, -1):
            dp[j] = dp[j] + dp[j - 1]
    return dp[k]

n, k = map(int, input("Enter n and k: ").split())
print(f"C({n},{k}) = {binomial(n, k)}")
Enter n and k: 10 3 C(10,3) = 120
Viva Questions
  1. Q: Why not just use the factorial formula n!/(k!(n-k)!)?
    A: Factorials overflow quickly for large n. DP avoids overflow by adding smaller numbers.
  2. Q: What is Pascal's Triangle?
    A: A triangular array where each entry is the sum of the two above it. Row n, column k gives C(n,k).
  3. Q: Time and space of optimized version?
    A: O(nk) time, O(k) space.
  4. Q: Why iterate right to left in the 1D version?
    A: To use previous row's values before overwriting them.
  5. Q: What does C(n,k) represent combinatorially?
    A: Number of ways to choose k items from n items, regardless of order.

Lab 4: Box Stacking Problem

๐Ÿ“˜ Syllabus Programโฑ๏ธ 40 min
Python
def max_stack_height(boxes):
    rot = []
    for h, w, d in boxes:
        dims = sorted([h, w, d])
        # Generate all 3 rotations
        rot.append((dims[0], max(dims[1],dims[2]), min(dims[1],dims[2])))
        rot.append((dims[1], max(dims[0],dims[2]), min(dims[0],dims[2])))
        rot.append((dims[2], max(dims[0],dims[1]), min(dims[0],dims[1])))

    rot.sort(key=lambda x: x[1]*x[2], reverse=True)
    n = len(rot)
    dp = [r[0] for r in rot]

    for i in range(1, n):
        for j in range(i):
            if rot[i][1] < rot[j][1] and rot[i][2] < rot[j][2]:
                dp[i] = max(dp[i], dp[j] + rot[i][0])

    return max(dp)

boxes = [(4,6,7), (1,2,3), (4,5,6)]
print(f"Max stack height: {max_stack_height(boxes)}")
Max stack height: 22
Viva Questions
  1. Q: Why do we generate 3 rotations per box?
    A: Each dimension can be the height. The base is formed by the other two dimensions.
  2. Q: Why sort by base area?
    A: Ensures that when checking box i against box j (j < i), box j has a larger base area. This is necessary for the LIS-like DP to work correctly.
  3. Q: What is the strict condition for stacking?
    A: Both width AND depth of the top box must be strictly less than the bottom box.
  4. Q: Can the same box type be used multiple times?
    A: Yes, because different rotations of the same box are treated as different boxes.
  5. Q: Time complexity?
    A: O((3n)ยฒ) = O(9nยฒ) = O(nยฒ) where n is the number of box types.

Lab 5: Integer Knapsack (0/1)

๐Ÿ“˜ Syllabus Programโฑ๏ธ 35 min
C++
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, W;
    cout << "Enter number of items and capacity: ";
    cin >> n >> W;
    vector<int> wt(n), val(n);
    cout << "Enter weight and value for each item:\n";
    for (int i = 0; i < n; i++) cin >> wt[i] >> val[i];

    vector<vector<int>> dp(n+1, vector<int>(W+1, 0));
    for (int i = 1; i <= n; i++)
        for (int w = 1; w <= W; w++) {
            dp[i][w] = dp[i-1][w];
            if (wt[i-1] <= w)
                dp[i][w] = max(dp[i][w], dp[i-1][w-wt[i-1]] + val[i-1]);
        }

    cout << "Maximum value: " << dp[n][W] << endl;

    // Backtrack to find selected items
    cout << "Selected items: ";
    int w = W;
    for (int i = n; i > 0; i--)
        if (dp[i][w] != dp[i-1][w]) {
            cout << i << " ";
            w -= wt[i-1];
        }
    return 0;
}
Enter number of items and capacity: 4 7 Enter weight and value for each item: 1 1 3 4 4 5 5 7 Maximum value: 9 Selected items: 3 2
Viva Questions
  1. Q: What's the difference between 0/1 and unbounded knapsack?
    A: 0/1: each item at most once. Unbounded: items can be repeated.
  2. Q: How do you backtrack to find selected items?
    A: Start at dp[n][W]. If dp[i][w] โ‰  dp[i-1][w], item i was included; subtract its weight and move to i-1.
  3. Q: Time complexity?
    A: O(n ร— W).
  4. Q: Is Knapsack polynomial or pseudo-polynomial?
    A: Pseudo-polynomial. W can be exponentially large relative to its bit representation.
  5. Q: How does 1D optimization work?
    A: Iterate weights right to left using a single 1D array of size W+1.

Lab 6: Edit Distance (Levenshtein)

๐Ÿ“˜ Syllabus Programโฑ๏ธ 30 min
Python
def edit_distance(A, B):
    m, n = len(A), len(B)
    dp = [[0]*(n+1) for _ in range(m+1)]

    for i in range(m+1): dp[i][0] = i
    for j in range(n+1): dp[0][j] = j

    for i in range(1, m+1):
        for j in range(1, n+1):
            if A[i-1] == B[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = 1 + min(dp[i-1][j],
                                   dp[i][j-1],
                                   dp[i-1][j-1])
    return dp[m][n]

A = input("Enter string A: ")
B = input("Enter string B: ")
print(f"Edit Distance: {edit_distance(A, B)}")
Enter string A: saturday Enter string B: sunday Edit Distance: 3
Viva Questions
  1. Q: What are the three operations in Edit Distance?
    A: Insert, Delete, Replace โ€” each costs 1.
  2. Q: What's the base case?
    A: dp[i][0] = i (delete all), dp[0][j] = j (insert all).
  3. Q: Real-world application?
    A: Spell checkers, DNA alignment, plagiarism detection, autocorrect.
  4. Q: Can operations have different costs?
    A: Yes! Weighted Edit Distance assigns different costs to insert/delete/replace.
  5. Q: How to print the actual operations?
    A: Backtrack from dp[m][n]: if diagonal with change โ†’ replace, if from above โ†’ delete, if from left โ†’ insert.

Lab 7: Balanced Partition

๐Ÿ“˜ Syllabus Programโฑ๏ธ 30 min
C++
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cout << "Enter array size: ";
    cin >> n;
    vector<int> arr(n);
    cout << "Enter elements: ";
    int S = 0;
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
        S += arr[i];
    }

    int half = S / 2;
    vector<bool> dp(half + 1, false);
    dp[0] = true;

    for (int i = 0; i < n; i++)
        for (int j = half; j >= arr[i]; j--)
            dp[j] = dp[j] || dp[j - arr[i]];

    for (int j = half; j >= 0; j--)
        if (dp[j]) {
            cout << "Minimum difference: " << S - 2 * j << endl;
            break;
        }
    return 0;
}
Enter array size: 4 Enter elements: 1 6 11 5 Minimum difference: 1
Viva Questions
  1. Q: How does Balanced Partition relate to Subset Sum?
    A: It reduces to finding a subset with sum closest to total/2.
  2. Q: Why iterate right to left in 1D optimization?
    A: To ensure each element is considered only once (0/1 constraint).
  3. Q: What's the minimum possible difference?
    A: 0 if total sum is even and an exact half-split exists, otherwise 1 (if odd sum).
  4. Q: Time complexity?
    A: O(n ร— S/2) where S is the total sum.
  5. Q: Can this handle negative numbers?
    A: Standard DP can't. Need offset or different formulation for negative values.
Section J

Industry Spotlight โ€” A Day in the Life

๐Ÿ‘ฉโ€๐Ÿ’ป Kavitha Rajan, 28 โ€” SDE-II at Amazon India, Hyderabad

Background: B.Tech in CSE from NIT Trichy. Started competitive programming on CodeChef in 2nd year. Became 5-star rated (2100+). Cracked Amazon's interview in final year โ€” 2 out of 4 interview rounds featured DP problems (Knapsack variant and LCS).

A Typical Day:

9:00 AM โ€” Morning standup with the Fulfillment Optimization team. Review metrics: package throughput, delivery route efficiency, warehouse packing utilization.

10:00 AM โ€” Working on a box-packing optimization algorithm for Amazon's Hyderabad warehouse. Uses a variant of the Box Stacking / Bin Packing problem to minimize wasted space in delivery trucks. "We saved 12% on shipping costs last quarter with our DP-based packer."

12:00 PM โ€” Code review for a teammate's implementation of a dynamic allocation algorithm. "I always check if the DP recurrence matches the problem's optimal substructure. That's where bugs hide."

2:00 PM โ€” Interview panel: conducting technical interviews for SDE-I candidates. "I always ask at least one DP question โ€” usually LIS or Edit Distance. It separates candidates who memorize from those who truly understand state transitions."

4:00 PM โ€” Profiling and optimizing a DP-based recommendation engine. Reduced memory from O(mร—n) to O(n) using space optimization โ€” exactly the technique from LCS.

6:00 PM โ€” Mentoring session with 2 interns. Teaching them to think in DP: "First define your states. Then write the recurrence on paper. Only then code."

DetailInfo
Tools Used DailyC++, Java, Python, AWS services, internal DP/optimization libraries
Entry Salary (SDE-I)โ‚น20โ€“30 LPA (Amazon India)
Current Salary (SDE-II, 4 yrs)โ‚น38โ€“50 LPA (including RSUs)
Interview Tip"Master these 7 DP problems. They cover 80% of DP interview questions at FAANG."
Companies Using DPAmazon, Google, Microsoft, Flipkart, Swiggy, PhonePe, Razorpay, CRED, Atlassian
Section K

Earn With It โ€” Interview Prep Coaching

๐Ÿ’ฐ Your Earning Path: Interview Prep Coaching (โ‚น15Kโ€“โ‚น50K/month)

The Opportunity: India has 1.5 million+ engineering students preparing for placement each year. Most struggle with Dynamic Programming โ€” the #1 topic in coding interviews. If you master these 7 DP problems, you can coach juniors and earn โ‚น15Kโ€“โ‚น50K/month.

How to Start Earning

Step 1: Build Your Proof (2โ€“4 weeks)

  • Solve 50+ DP problems on LeetCode/CodeForces
  • Get 4-star+ rating on CodeChef or 1600+ on Codeforces
  • Create a blog/YouTube channel explaining DP problems

Step 2: Start Coaching (Month 1โ€“2)

  • Offer 1-on-1 DP coaching to 3rd/4th year students at โ‚น500โ€“โ‚น1,000/session
  • Create a "DP Masterclass" (7 problems in 7 sessions) for โ‚น3,000โ€“โ‚น5,000
  • Post on LinkedIn: "Cracked FAANG DP problems. DM for coaching."

Step 3: Scale (Month 3+)

  • Group sessions (5โ€“10 students): โ‚น1,000โ€“โ‚น2,000/student for a 10-session course
  • Create pre-recorded DP courses on Unacademy/YouTube: passive income
  • Conduct mock interviews: โ‚น500โ€“โ‚น1,500 per session
ServiceRateMonthly Potential
1-on-1 DP Coachingโ‚น800โ€“โ‚น1,500/sessionโ‚น8Kโ€“โ‚น15K (10โ€“12 sessions/month)
Group DP Masterclassโ‚น3,000โ€“โ‚น5,000/student (7 sessions)โ‚น15Kโ€“โ‚น25K (5 students)
Mock Interviewsโ‚น500โ€“โ‚น1,500/sessionโ‚น5Kโ€“โ‚น15K (10 sessions)
YouTube/Blog AdsVariesโ‚น2Kโ€“โ‚น10K (once established)
The best part: teaching DP makes YOU better at DP. Every coaching session reinforces your own understanding. Students who coach others score 30% higher in their own interviews (based on InterviewBit data). You earn money AND improve your skills simultaneously.
Platform suggestions for Indian students: Start local (WhatsApp groups, college communities), then scale to Topmate.io (โ‚น500+ per session), Preply, or create your own Telegram group. Many IIT/NIT students earn โ‚น20Kโ€“โ‚น40K/month coaching placement aspirants.
Section L

Chapter Summary โ€” DP Problem Classification

๐Ÿ“‹ What You've Mastered

In this unit, you've learned 7 classic Dynamic Programming problems, each with complete recurrences, table traces, dual-language code, complexity analysis, and space optimizations. These 7 problems form the backbone of 80%+ of DP interview questions at top tech companies.

DP Problem Classification Table

ProblemTypeStateTimeSpaceKey Technique
Binomial CoefficientCombinatorialdp[i][j]O(nk)O(k)Pascal's Triangle, 1D optimization
Box StackingLIS Variantdp[i]O(nยฒ)O(n)Rotation generation, sort by base area
0/1 KnapsackSubset Selectiondp[i][w]O(nW)O(W)Include/Exclude, right-to-left 1D
Edit DistanceString DPdp[i][j]O(mn)O(mn)3-way min (insert/delete/replace)
LISSubsequencedp[i]O(nยฒ) / O(n log n)O(n)Binary search for O(n log n)
LCSString DPdp[i][j]O(mn)O(mn)Match/skip, backtracking for string
Balanced PartitionSubset Sumdp[j] boolO(nS)O(S)Reduce to subset sum with target S/2

The DP Problem-Solving Framework

๐Ÿง  5-Step DP Recipe (Works for ANY DP Problem)

Step 1 โ€” Define the State: What does dp[i] or dp[i][j] represent? This is the hardest step.

Step 2 โ€” Write the Recurrence: Express dp[i][j] in terms of smaller subproblems.

Step 3 โ€” Define Base Cases: What are the trivially solvable cases?

Step 4 โ€” Determine Fill Order: Bottom-up (small โ†’ large) or top-down (memoization)?

Step 5 โ€” Extract the Answer: Where in the table is the final answer? Do you need backtracking?

Connections Between Problems

ConnectionInsight
Balanced Partition โ†’ KnapsackPartition is Knapsack with capacity = S/2 and value = weight
Box Stacking โ†’ LISStacking is 2D LIS after rotation generation
Longest Palindromic Subsequence โ†’ LCSLPS(S) = LCS(S, reverse(S))
LCS โ†” Edit DistanceFor insert/delete only: EditDist = m + n โˆ’ 2ร—LCS
Coin Change โ†’ Unbounded KnapsackSame DP but items can be reused
Google's internal data shows that DP is the #1 topic that correlates with interview success. Candidates who can solve DP problems within 30 minutes have a 3ร— higher offer rate than those who can't. The 7 problems in this unit cover the patterns behind 80% of all DP interview questions.
Section M

Earning Checkpoint โ€” Self-Assessment

SkillTool / TechniquePortfolio DeliverableEarn-Ready?
Binomial CoefficientPascal's Triangle DPWorking C++/Python codeโœ… Yes โ€” foundation for combinatorics questions
Box StackingLIS variant, rotation generationFull solution with traceโœ… Yes โ€” logistics optimization interviews
0/1 Knapsack2D DP + 1D optimizationSolution with backtrackingโœ… Yes โ€” appears in 30%+ coding interviews
Edit DistanceString DP, 3-way recurrenceFull solution + operations listโœ… Yes โ€” NLP/bioinformatics interviews
LISO(nยฒ) DP + O(n log n) binary searchBoth approaches implementedโœ… Yes โ€” core competitive programming skill
LCSString DP + backtrackingSolution with actual subsequenceโœ… Yes โ€” diff tools, DNA matching
Balanced PartitionSubset Sum reductionWorking solutionโœ… Yes โ€” resource allocation problems
Interview CoachingTeaching DP to juniors7-problem masterclass curriculumโœ… Yes โ€” โ‚น15Kโ€“โ‚น50K/month potential
Minimum Viable Interview Prep: Master these 7 problems + their variations. Practice each problem at least 3 times (once reading, once tracing, once coding from memory). This covers the DP portion of 80% of FAANG coding interviews. Combine with your coaching portfolio = earn โ‚น15Kโ€“โ‚น50K/month while preparing for your own placements.

๐ŸŽฏ Post-Unit Action Items

  1. โœ… Solve all 7 problems from memory (no reference)
  2. โœ… Complete all 5 tracing exercises (Section E)
  3. โœ… Solve at least 5 programming problems from the Problem Set
  4. โœ… Score 24/30+ on the MCQ assessment
  5. โœ… Solve 20+ DP problems on LeetCode (Easyโ†’Medium)
  6. โœ… Create your "DP Masterclass" outline for coaching
  7. โœ… Apply to at least 3 companies with DP in their interview process

โœ… Unit 5 complete. You now think in states and transitions. Ready for Unit 6!

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