0% found this document useful (0 votes)
2 views18 pages

DP-1

The document outlines several dynamic programming problems, including the Maximum Value Contiguous Subsequence, Making Change, the Integer Knapsack Problem, Box Stacking, and Building Bridges. Each problem is presented with a statement, intuition, detailed solutions, examples, and complexity analysis. The solutions utilize dynamic programming techniques to efficiently solve the respective problems, often with time complexities of O(n) or O(n × C).

Uploaded by

Amit Rai
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views18 pages

DP-1

The document outlines several dynamic programming problems, including the Maximum Value Contiguous Subsequence, Making Change, the Integer Knapsack Problem, Box Stacking, and Building Bridges. Each problem is presented with a statement, intuition, detailed solutions, examples, and complexity analysis. The solutions utilize dynamic programming techniques to efficiently solve the respective problems, often with time complexities of O(n) or O(n × C).

Uploaded by

Amit Rai
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Dynamic Programming Problems & Detailed Solutions

1. Maximum Value Contiguous Subsequence (The Maximum


Subarray Problem)

Problem Statement:

Given a sequence of n real numbers A₁, A₂, ..., A , determine a contiguous

subsequence Aᵢ, ..., Aⱼ for which the sum of elements in the subsequence is

maximized.

What it is asking:

Find a contiguous block of elements within a one-dimensional array that has the

largest possible sum. A subsequence is "contiguous" if it consists of consecutive

elements from the original array. For example, in the array [-2, 1, -3, 4, -1, 2, 1, -5, 4],

the contiguous subsequence with the maximum sum is [4, -1, 2, 1], with a sum of 6.

Intuition:

The brute-force approach would be to check every possible starting and ending

point, which takes O(n²) time. The elegant DP approach, known as Kadane's

Algorithm, solves it in O(n) time. The core idea is to make a single pass through the

array and, for each position, decide: "Is it better to start a new contiguous array at

this element, or should I add this element to the best contiguous array ending at the

previous position?"
We track two things:

1.​ Local Maximum (current_max): The maximum sum of a contiguous subarray

that ends at the current element.

2.​ Global Maximum (global_max): The maximum sum we have seen so far

across all positions.

Detailed Solution (Kadane's Algorithm):

1.​ Initialization:

○​ Let current_max = A[0]. This represents the best sum we can get

ending at the first element.

○​ Let global_max = A[0]. This is our overall best sum so far.

2.​ Iteration:

○​ For each element A[i] in the array, starting from the second element (i

= 1):

■​ Update the local maximum: The best sum ending at i is either

the element itself, or the element added to the best sum ending

at i-1. We choose the maximum of these two options.

■​ text
■​ current_max = max(A[i], current_max + A[i])

■​ Update the global maximum: If the local maximum we just

calculated is better than our known global maximum, we update

it.

■​ text
■​ global_max = max(global_max, current_max)

3.​ Result:

○​ After iterating through the entire array, the value of global_max is the

sum of the Maximum Value Contiguous Subsequence.


Example:

Array: [-2, 1, -3, 4, -1, 2, 1, -5, 4]

i A[i] current_max = max(A[i], global_max =

current_max + A[i]) max(global_max,

current_max)

0 -2 current_max = -2 global_max = -2

1 1 max(1, -2+1) = max(1, max(-2, 1) = 1

-1) = 1

2 -3 max(-3, 1-3) = max(-3, max(1, -2) = 1

-2) = -2

3 4 max(4, -2+4) = max(4, 2) max(1, 4) = 4

= 4

4 -1 max(-1, 4-1) = max(-1, max(4, 3) = 4

3) = 3

5 2 max(2, 3+2) = max(2, 5) max(4, 5) = 5

= 5

6 1 max(1, 5+1) = max(1, 6) max(5, 6) = 6

= 6

7 -5 max(-5, 6-5) = max(-5, max(6, 1) = 6

1) = 1

8 4 max(4, 1+4) = max(4, 5) max(6, 5) = 6

= 5
Final Answer: global_max = 6

Complexity: Time: O(n), Space: O(1)

2. Making Change (Coin Change - Minimum Number of


Coins)

Problem Statement:

You are given n types of coin denominations of values v₁ < v₂ < ... < v (all integers).

Assume v₁ = 1, so you can always make change for any amount of money C. Give an

algorithm which makes change for an amount of money C with as few coins as

possible.

What it is asking:

Find the smallest number of coins needed to make a given amount C, given an

unlimited supply of coins of each denomination. For example, with coins [1, 5, 10, 25]

and C = 47, the minimum number of coins is 5 (e.g., 25 + 10 + 10 + 1 + 1).

Intuition:

We can solve this using a "bottom-up" dynamic programming approach. We will

solve the problem for every amount from 0 up to C. For a specific amount j, the

minimum number of coins required is one more than the minimum number required

for the amount (j - vᵢ), where vᵢ is a coin value that is less than or equal to j. We try all

possible coins vᵢ and choose the one that gives the minimum count.
Detailed Solution:

1.​ Define the DP Array:

○​ Let dp be an array of size C + 1.

○​ dp[j] will store the minimum number of coins needed to make the

amount j.

2.​ Initialization:

○​ dp[0] = 0 (Zero coins are needed to make amount 0).

○​ For all j from 1 to C, initialize dp[j] = infinity (or a very large

number like C + 1). This signifies that we haven't found a way to make

that amount yet.

3.​ Fill the DP Table:

○​ For each amount j from 1 to C:

■​ For each coin denomination vᵢ in the list of coins:

■​ If the coin value is less than or equal to the current

amount (vᵢ <= j), then we can use this coin.

■​ The number of coins needed would be 1 (for the current

coin vᵢ) plus the number of coins needed for the

remaining amount j - vᵢ, which is dp[j - vᵢ].

■​ We update dp[j] to be the minimum of its current value

and this new candidate value.

■​ text
■​ dp[j] = min(dp[j], 1 + dp[j - vᵢ])

4.​ Result:

○​ After the loops complete, dp[C] will contain the minimum number of

coins needed to make amount C.


Example:

Coins: [1, 5, 10, 25], C = 47

We build the dp table for amounts 0 to 47. A few key values:

●​ dp[0] = 0

●​ dp[1] = 1 (1)

●​ dp[2] = 2 (1+1)

●​ ...

●​ dp[5] = 1 (5)

●​ dp[6] = 2 (5+1)

●​ ...

●​ dp[10] = 1 (10)

●​ dp[11] = 2 (10+1)

●​ ...

●​ dp[25] = 1 (25)

●​ dp[26] = 2 (25+1)

●​ ...

●​ dp[47] = 5 (25 + 10 + 10 + 1 + 1)

Final Answer: dp[47] = 5

Complexity: Time: O(n × C), Space: O(C)


3. The Integer Knapsack Problem (Unbounded Knapsack)

Problem Statement:

You have n types of items, where the i-th item type has an integer size sᵢ and a real

value vᵢ. You are trying to fill a knapsack of total capacity C with a selection of items

of maximum value. You can add multiple items of the same type to the knapsack.

What it is asking:

This is the Unbounded Knapsack Problem. You have a knapsack with a fixed

capacity C. You have unlimited quantities of n different item types, each with a

specific size and value. Your goal is to choose items (including multiple of the same

type) such that the total size is at most C and the total value is maximized.

Intuition:

Similar to the coin change problem, we use a DP array where dp[j] represents the

maximum value achievable with a knapsack capacity of j. For each capacity j, we

consider every item type i. If the item fits (sᵢ <= j), we check if including it (and then

optimally filling the remaining capacity j - sᵢ) gives us a higher total value than we

currently have for capacity j.

Detailed Solution:

1.​ Define the DP Array:

○​ Let dp be an array of size C + 1.

○​ dp[j] will store the maximum value achievable with capacity j.

2.​ Initialization:
○​ dp[0] = 0 (A knapsack with 0 capacity holds 0 value).

○​ For j from 1 to C, we can initialize dp[j] = 0.

3.​ Fill the DP Table:

○​ For each capacity j from 1 to C:

■​ For each item type i from 1 to n:

■​ If the item's size sᵢ is less than or equal to j (sᵢ <= j),

then we can consider taking it.

■​ The candidate value is the value of item i plus the

maximum value achievable with the remaining capacity:

vᵢ + dp[j - sᵢ].

■​ We update dp[j] to be the maximum of its current value

and this candidate value.

■​ text
■​ dp[j] = max(dp[j], vᵢ + dp[j - sᵢ])

4.​ Result:

○​ The solution is the value dp[C], which is the maximum value

achievable with the full capacity C.

Example:

Items: (Size, Value) = [(2, 3), (3, 4), (4, 5), (5, 6)], C = 10

We build the dp table from 0 to 10:

●​ dp[0] = 0

●​ dp[1] = 0 (no item fits)

●​ dp[2] = max(0, 3 + dp[0]) = 3

●​ dp[3] = max(0, 4 + dp[0], 3 + dp[1]) = max(0, 4, 3) = 4

●​ dp[4] = max(0, 5 + dp[0], 3 + dp[2], 4 + dp[1]) = max(0, 5, 6, 4)

= 6 (using two of item 1)


●​ dp[5] = max(0, 6 + dp[0], 3 + dp[3], 4 + dp[2], 5 + dp[1]) =

max(0, 6, 7, 7, 5) = 7

●​ ... continue to dp[10] ...

●​ One optimal solution for C = 10 is to take five of item 1 (size 2, value 3), giving

a total value of 15.

Final Answer: dp[10] = 15

Complexity: Time: O(n × C), Space: O(C)

4. Box Stacking

Problem Statement:

You are given a set of n types of rectangular 3-D boxes, where the i-th box has height

hᵢ, width wᵢ, and depth dᵢ (all real numbers). You want to create a stack of boxes

which is as tall as possible, but you can only stack a box on top of another box if the

dimensions of the 2-D base of the lower box are each strictly larger than those of the

2-D base of the higher box. Of course, you can rotate a box so that any side functions

as its base. It is also allowable to use multiple instances of the same type of box.

What it is asking:

Find the tallest possible stack of boxes. A box can be placed on top of another only if

both its base dimensions (length and width) are strictly smaller than the base

dimensions of the box below. Boxes can be rotated, meaning any of the three faces

can be the base. You can use multiple copies of the same box.
Intuition:

This problem can be transformed into finding the Longest Increasing Subsequence

(LIS) on a list of box rotations, sorted by base area. The idea is to generate all

possible rotations for each box (since we can use any face as the base). Then, we

sort this list of "box instances" in decreasing order of base area. This ensures that a

box can only be placed on boxes that come before it in the sorted list (if the

dimensions allow). We then perform a variation of the LIS algorithm where we

maximize the sum of heights instead of the length of the sequence.

Detailed Solution:

1.​ Generate all rotations:

○​ For each original box, create 3 different box representations, each with

a different face as the base. To avoid duplicate checks, we enforce the

convention: base_length >= base_width.

○​ For a box (h, w, d), the three rotations are:

■​ Rotation 1: Base = (max(w, d), min(w, d)), Height = h

■​ Rotation 2: Base = (max(h, d), min(h, d)), Height = w

■​ Rotation 3: Base = (max(h, w), min(h, w)), Height = d

○​ This gives us an array rotated_boxes of size 3n. Each element is

(base_length, base_width, height).

2.​ Sort the rotations:

○​ Sort the rotated_boxes in decreasing order of base area (base_length

× base_width). This helps because a box with larger area can only be

below a box with smaller area.

3.​ Dynamic Programming (LIS variant):

○​ Let dp[i] be the maximum possible height achievable when the i-th

box (from the sorted list) is at the top of the stack.


○​ Initialize dp[i] = height[i] for all i. The worst-case stack is just the

box by itself.

○​ For each box i from 1 to 3n-1:

■​ For each box j from 0 to i-1:

■​ Check if box j can be placed below box i. This is true if:

■​ text
■​ (base_length[j] > base_length[i]) and
(base_width[j] > base_width[i])

■​ If it can, then we can form a stack with box i on top of the

stack ending with box j. The total height would be:

■​ text
■​ height[i] + dp[j]

■​ Update: dp[i] = max(dp[i], height[i] + dp[j])

4.​ Result:

○​ The answer is the maximum value found in the dp array.

Example:

Consider boxes: [(1, 2, 3), (4, 5, 6)]

Generate rotations:

●​ Box 1: (3, 2, 1), (3, 1, 2), (2, 1, 3)

●​ Box 2: (6, 5, 4), (6, 4, 5), (5, 4, 6)

Sort by base area and apply LIS variant to find maximum height.

Final Answer: Maximum stack height from DP calculation.

Complexity: Time: O((3n)²) = O(n²), Space: O(n)


5. Building Bridges

Problem Statement:

Consider a 2-D map with a horizontal river passing through its center. There are n

cities on the southern bank with x-coordinates a₁, a₂, ..., a and n cities on the

northern bank with x-coordinates b₁, b₂, ..., b . You want to connect as many

north-south pairs of cities as possible with bridges such that no two bridges cross.

When connecting cities, you are only allowed to connect the i-th city on the northern

bank to the i-th city on the southern bank.

What it is asking:

We are given two sequences of coordinates: a (south) and b (north). We can only

connect city i on the north to city i on the south. A bridge is a straight line from (aᵢ,

south_bank) to (bᵢ, north_bank). Two bridges cross if the lines intersect. The goal

is to select the maximum number of non-crossing bridges.

Intuition:

Two bridges (aᵢ, bᵢ) and (a , b ) will not cross if and only if (aᵢ < a and bᵢ <

b ) OR (aᵢ > a and bᵢ > b ). In other words, the pairs (aᵢ, bᵢ) must be in

increasing order in both a and b. This is exactly the definition of an increasing

sequence in the pairs. Therefore, the problem reduces to: given a set of pairs (aᵢ,

bᵢ), find the longest sequence of pairs such that both the a values and the b values

are strictly increasing. This is the Longest Increasing Subsequence (LIS) problem on

the sequence of bᵢ values, after sorting the pairs by aᵢ.


Detailed Solution:

1.​ Create Pairs:

○​ Create an array pairs where each element is (aᵢ, bᵢ).

2.​ Sort the Pairs:

○​ Sort the pairs array by the southern coordinate aᵢ. If two aᵢ are equal,

sort by the northern coordinate bᵢ.

3.​ Find the Longest Increasing Subsequence (LIS):

○​ Extract the sequence of bᵢ values from the sorted pairs array.

○​ Find the LIS of this bᵢ sequence using the standard O(n log n) algorithm:

■​ Let lis be an array that stores the smallest possible tail value

for increasing subsequences.

■​ Initialize lis as empty.

■​ For each b_value in the sequence:

■​ If b_value is greater than the last element in lis, append

it.

■​ Else, use binary search to find the smallest element in lis

that is greater than or equal to b_value, and replace it.

4.​ Result:

○​ The length of the lis array is the maximum number of non-crossing

bridges.

Example:

Let a = [5, 1, 3, 2, 4] and b = [3, 1, 2, 4, 5].

1.​ Create pairs: [(5,3), (1,1), (3,2), (2,4), (4,5)]

2.​ Sort by a: [(1,1), (2,4), (3,2), (4,5), (5,3)]

3.​ Extract b sequence: [1, 4, 2, 5, 3]


4.​ Find LIS of [1, 4, 2, 5, 3]:

○​ Start: lis = []

○​ 1 → lis = [1]

○​ 4 → lis = [1, 4]

○​ 2 → replace 4 with 2 → lis = [1, 2]

○​ 5 → lis = [1, 2, 5]

○​ 3 → replace 5 with 3 → lis = [1, 2, 3]

○​ Length of LIS = 3

Final Answer: 3 non-crossing bridges (Connections: (1,1), (3,2), (5,3))

Complexity: Time: O(n log n), Space: O(n)

6. Balanced Partition

Problem Statement:

You have a set of n integers each in the range 0...K. Partition these integers into two

subsets such that you minimize |S1 - S2|, where S1 and S2 denote the sums of the

elements in each of the two subsets.

What it is asking:

This is a classic partition problem. We need to split an array of integers into two

subsets such that the absolute difference between the sums of the two subsets is as

small as possible. For example, for the set [1, 6, 11, 5], the minimum difference

is 1 (Partitions: [1, 5, 6] sum=12 and [11] sum=11, difference=1).


Intuition:

Let W be the total sum of all numbers. If one subset has sum S1, the other has sum W

- S1. The difference is |S1 - (W - S1)| = |2S1 - W|. To minimize this, we want

S1 to be as close as possible to W/2. So, the problem reduces to: find a subset of the

numbers whose sum is as close as possible to W/2 without exceeding it. This is a

subset sum problem.

Detailed Solution:

1.​ Calculate Total Sum:

○​ Let W = sum(arr)

2.​ Subset Sum DP:

○​ We want to know, for values up to W/2, which sums are achievable by

some subset.

○​ Let dp be a boolean array of size (W//2 + 1). dp[s] will be true if

there exists a subset that sums to s.

○​ Initialize dp[0] = true (the empty subset sums to 0).

○​ For all other s, initialize dp[s] = false.

3.​ Fill the DP Table:

○​ For each number num in the array:

■​ Iterate s from W//2 down to num (iterating backwards prevents

reusing the same element multiple times).

■​ If dp[s - num] is true, then we can form the sum s by including

num. So, set dp[s] = true.

4.​ Find the Best Sum:

○​ After processing all numbers, find the largest index s (from W//2 down

to 0) for which dp[s] is true. Let this sum be S1.

○​ The other subset will have sum S2 = W - S1.


○​ The minimum difference is |S1 - S2| = |2S1 - W| = W - 2 × S1.

Example:

Array: [1, 6, 11, 5], W = 23, W/2 = 11.5. We check sums up to 11.

dp initialization: dp[0] = true.

●​ Process 1: dp[1] = true

●​ Process 6: dp[6], dp[7] = true

●​ Process 11: dp[11] = true (from dp[0])

●​ Process 5: dp[5], dp[6], dp[7], dp[11], dp[12] become true (but we

only care up to 11)

The largest achievable sum <= 11 is s = 11.​

Minimum difference = 23 - 2 × 11 = 1

Final Answer: Minimum Difference = 1

Complexity: Time: O(n × W), Space: O(W)

7. Edit Distance (Levenshtein Distance)

Problem Statement:

Given two text strings A of length n and B of length m, you want to transform A into B

with a minimum number of operations of the following types: delete a character from

A, insert a character into A, or change some character in A into a new character. The

minimal number of such operations required to transform A into B is called the edit

distance between A and B.


What it is asking:

Find the minimum number of single-character edits (insertions, deletions,

substitutions) required to change one string into another. For example, the edit

distance between "kitten" and "sitting" is 3 (k→s, e→i, insert g).

Intuition:

We use a 2D DP table dp where dp[i][j] represents the edit distance between the

first i characters of string A and the first j characters of string B. The value at

dp[i][j] is built from its smaller subproblems by considering the three possible

operations we can perform on the last character of the prefix of A.

Detailed Solution:

1.​ Define the DP Table:

○​ Let dp be a 2D array of size (n+1) × (m+1).

○​ dp[i][j] = edit distance between A[0..i-1] and B[0..j-1].

2.​ Base Cases:

○​ dp[0][j] = j: To convert an empty string to B[0..j-1], we need j

insertions.

○​ dp[i][0] = i: To convert A[0..i-1] to an empty string, we need i

deletions.

3.​ Recurrence Relation:

○​ For each i from 1 to n and each j from 1 to m:


■​ If A[i-1] == B[j-1]:

■​ The last characters match. No operation is needed.

■​ dp[i][j] = dp[i-1][j-1]

■​ Else:

■​ We have three choices, and take the minimum cost:

1.​ Delete from A: 1 + dp[i-1][j]

2.​ Insert into A: 1 + dp[i][j-1]

3.​ Replace in A: 1 + dp[i-1][j-1]

■​ dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1],

dp[i-1][j-1])

4.​ Result:

○​ The edit distance between the two strings is dp[n][m].

Example:

A = "kitten", B = "sitting"

The final dp[6][7] = 3 through table calculation.

Final Answer: dp[n][m] = 3

Complexity: Time: O(n × m), Space: O(n × m)

You might also like