Matrix Chain Multiplication
Matrix Chain Multiplication
Matrix Chain Multiplication
Problem
You are given a chain of matrices A1, A2, A3, ... An. You must find the cheapest way to multiply them all.
The order of multiplication changes the total work, even though the final answer is the same. So we need to decide where to put the parentheses to get the minimum number of multiplications.
You are given an array nums of size n. The size of matrix Ai is nums[i - 1] x nums[i].
Return the minimum number of multiplications needed to multiply the whole chain.
Examples
Example 1
Input: nums = [10, 15, 20, 25]
Output: 8000
The matrices are:
A1is10 x 15A2is15 x 20A3is20 x 25
There are two ways to multiply them:
A1 * (A2 * A3)needs 11250 multiplications.(A1 * A2) * A3needs 8000 multiplications.
The minimum is 8000.
Example 2
Input: nums = [4, 2, 3]
Output: 24
- There are only two matrices:
A1is4 x 2andA2is2 x 3. - There is only one way to multiply them.
- The cost is
4 * 2 * 3 = 24.
Basic Rule You Need to Know
When we multiply a matrix of size a x b with a matrix of size b x c:
- The result has size
a x c. - The number of multiplications is
a * b * c.
This one rule is the base of the whole solution.
Main Idea
This problem uses a pattern called Partition DP. We use it when a problem can be split in many ways, and we want the best split.
Let f(i, j) mean: the minimum cost to multiply the matrices from Ai to Aj.
To solve it, we follow these steps:
- Pick a split point
k, wherei <= k < j. - Multiply the left part
Ai ... Akfirst. - Multiply the right part
Ak+1 ... Ajfirst. - Then multiply the two results together.
- Try every possible
kand keep the smallest cost.
How to Find the Cost of One Split
For a split at k, the total cost has three parts:
- Left part:
f(i, k) - Right part:
f(k + 1, j) - Joining both parts:
p[i - 1] * p[k] * p[j]
Why is the joining cost p[i - 1] * p[k] * p[j]?
- The left part (
Ai ... Ak) gives one matrix of sizep[i - 1] x p[k]. - The right part (
Ak+1 ... Aj) gives one matrix of sizep[k] x p[j]. - Multiplying these two matrices costs
p[i - 1] * p[k] * p[j].
So the formula is:
cost = f(i, k) + f(k + 1, j) + p[i - 1] * p[k] * p[j]
We take the minimum of this cost over all values of k.
Base Case
- If
i === j, there is only one matrix. - We do not need to multiply anything, so the cost is
0.
Why We Need Memoization
The same sub-problem, like f(2, 3), is needed again and again from different splits. If we solve it every time, the work grows very fast.
So we use a table called dp. We save the answer of each f(i, j) the first time we solve it. Next time, we simply read it from the table.
Solution: Recursion + Memoization (Top-Down)
function matrixChainOrder(p) {
const n = p.length;
// Initialize memoization table with -1
const dp = Array.from({ length: n }, () => Array(n).fill(-1));
function solve(i, j) {
// Base case: single matrix requires 0 operations
if (i === j) return 0;
// Return cached result if available
if (dp[i][j] !== -1) return dp[i][j];
let mini = Infinity;
// Try all possible partitions k
for (let k = i; k < j; k++) {
let steps = p[i - 1] * p[k] * p[j] + solve(i, k) + solve(k + 1, j);
if (steps < mini) {
mini = steps;
}
}
return (dp[i][j] = mini);
}
// Start with the range covering all matrices (1 to n - 1)
return solve(1, n - 1);
}
How the Code Works
Let us go through the code step by step.
Step 1: Read the Input
pis the array of dimensions.n = p.length. If there arennumbers, there aren - 1matrices.- Matrix
Aihas sizep[i - 1] x p[i]. - Matrices are numbered from
1ton - 1.
Step 2: Create the dp Table
dp[i][j]stores the minimum cost to multiply matricesAitoAj.- We fill the whole table with
-1. This means "not solved yet". - We use
-1because a real cost can never be negative. - Row
0and column0are not used, because matrix numbering starts from1.
Step 3: Write the solve(i, j) Function
- Check the base case. If
i === j, we return0. - Check the saved answer. If
dp[i][j]is not-1, we already solved it, so we return it. - Set
mini = Infinity. This variable keeps the smallest cost we find. We start with a very big number, so any real cost is smaller. - Loop over
kfromitoj - 1. Each value ofkis one way to split the chain. - Calculate
stepsfor each split. We use the formulap[i - 1] * p[k] * p[j] + solve(i, k) + solve(k + 1, j). - Update
mini. Ifstepsis smaller thanmini, we save it. - Save and return. We store
miniindp[i][j]and return it.
Step 4: Start the Recursion
- We call
solve(1, n - 1). - This means: find the best cost to multiply all matrices, from the first to the last.
Dry Run
Let us run the code for p = [10, 15, 20, 25].
Here n = 4, so we have 3 matrices. We call solve(1, 3).
Split at k = 1:
- Left part:
solve(1, 1) = 0. - Right part:
solve(2, 3). This isp[1] * p[2] * p[3] = 15 * 20 * 25 = 7500. - Joining cost:
p[0] * p[1] * p[3] = 10 * 15 * 25 = 3750. - Total:
0 + 7500 + 3750 = 11250.
Split at k = 2:
- Left part:
solve(1, 2). This isp[0] * p[1] * p[2] = 10 * 15 * 20 = 3000. - Right part:
solve(3, 3) = 0. - Joining cost:
p[0] * p[2] * p[3] = 10 * 20 * 25 = 5000. - Total:
3000 + 0 + 5000 = 8000.
Final answer: min(11250, 8000) = 8000.
This matches the expected output. The best way is (A1 * A2) * A3.
Complexity
- Time Complexity:
O(n³)nis the length of the arrayp.- There are about
n * ndifferent states(i, j). - Each state is solved only once, thanks to memoization.
- Each state runs a loop over
k, which takes up toO(n). - So the total is
n * n * n = O(n³).
- Space Complexity:
O(n²)- The
dptable hasn * ncells. - The recursion stack also uses up to
O(n)extra space. - The table is the bigger part, so the total is
O(n²).
- The
Without memoization, the same code would take exponential time.
Summary
- This is a Partition DP problem.
- The cost of multiplying an
a x bmatrix with ab x cmatrix isa * b * c. solve(i, j)gives the minimum cost to multiply matricesAitoAj.- We try every split point
kand take the minimum cost. - The cost of one split is
solve(i, k) + solve(k + 1, j) + p[i - 1] * p[k] * p[j]. - If
i === j, the cost is0, because there is only one matrix. - The
dptable saves answers, so we never solve the same sub-problem twice. - The solution runs in
O(n³)time and usesO(n²)space.