Pascal's Triangle II (Row Generation)¶
Question¶
Given a 1-indexed integer \(r\), return the \(r^{\text{th}}\) row of Pascal's Triangle. In Pascal's Triangle, each number is the sum of the two numbers directly above it. Goal: Achieve \(O(r)\) time and \(O(1)\) auxiliary space.
Solution¶
Pattern¶
Multiplicative Combinatorial Formula Instead of calculating factorials or summing previous rows, we compute \(\binom{n}{k}\) using the value of \(\binom{n}{k-1}\).
How to Identify¶
- The problem asks for a specific row of Pascal's triangle.
- The constraints require a linear time \(O(n)\) solution.
- The context involves combinations (\(nCr\)).
Description¶
Step-by-step explanation:
- Recognize that the \(r^{\text{th}}\) row (1-indexed) corresponds to combinations \(\binom{n}{0}, \binom{n}{1}, \dots, \binom{n}{n}\) where \(n = r - 1\).
- Start with the first element: \(\text{ans}[0] = 1\).
- To find the next element at index \(i\), use the previous element: $\(\text{Current} = \text{Previous} \times \frac{n - i + 1}{i}\)$
- Key implementation detail: Multiply the previous value by \((n - i + 1)\) first, then divide by \(i\). This ensures the result remains an integer at each step.
- Critical Guard: Use a 64-bit integer (
long) for the multiplication to prevent overflow before the division brings the value back within 32-bit range.
The Intuition¶
Think of the transition between terms in a binomial expansion. Each term is a ratio of the previous one. We are essentially moving the "choice" pointer across the row. The formula \(\frac{n-i+1}{i}\) represents the ratio of how many ways we can choose \(i\) items versus \(i-1\) items.
Complexity¶
| Label | Worst | Average |
|---|---|---|
| Time Complexity | \(O(r)\) | \(O(r)\) |
| Space Complexity | \(O(1)\) | \(O(1)\) |
Time Complexity¶
We calculate each of the \(r\) elements exactly once using a constant number of arithmetic operations.
Space Complexity¶
We use \(O(1)\) auxiliary space if we do not count the required output array.
Code¶
class Solution {
public int[] pascalTriangleII(int r) {
// Pascal's row r (1-indexed) has r elements.
// n is the row index in combinatorial notation (0-indexed).
int n = r - 1;
int[] row = new int[r];
row[0] = 1; // nC0 is always 1
// We use a long to store the running product to prevent overflow
// during the multiplication step.
long currentVal = 1;
for (int i = 1; i < r; i++) {
// Formula: nCi = nC(i-1) * (n - i + 1) / i
currentVal = currentVal * (n - i + 1) / i;
row[i] = (int) currentVal;
}
return row;
}
}
Caveats¶
- Integer Overflow: Even if the final answer fits in an
int, the intermediate productcurrentVal * (n - i + 1)can easily exceed \(2 \times 10^9\). - Division Order: You cannot divide before you multiply ($ (currentVal / i) * (n - i + 1) $) because integer division will truncate the result, leading to incorrect values.
Concepts to Think About¶
- Binomial Theorem: Each row represents the coefficients of \((x+y)^n\).
- Symmetry: Pascal's triangle is symmetric (\(\binom{n}{k} = \binom{n}{n-k}\)). You could technically optimize by only calculating half the row and mirroring it, though the complexity remains \(O(r)\).
- Dynamic Programming: The \(O(r^2)\) approach is essentially DP (\(dp[i][j] = dp[i-1][j-1] + dp[i-1][j]\)).
- Space Compression: If you were asked to generate all rows up to \(r\) in \(O(r)\) space, you would use a single array and update it backwards to avoid overwriting values you still need.
Logical Follow-up¶
Question: How would you find the value at a specific coordinate \((r, c)\) without generating the whole row?
Solution: Directly use the formula \(\binom{r-1}{c-1} = \frac{(r-1)!}{(c-1)!(r-c)!}\). However, for large values, the multiplicative loop approach is still safer than calculating factorials directly.