Chapter 57
Home
LCS with a full 2D table uses O(N×M) memory. But dp[i][*] only
depends on dp[i-1][*] and dp[i][*-1]. By keeping
just two rows, we drop to O(min(N,M)) without changing time complexity.
vector> dp(n + 1, vector (m + 1, 0)); // N=5000, M=5000: ~100 MB (may exceed memory limit)
int lcs_optimized(string& s, string& t) {
int n = s.size(), m = t.size();
vector prev(m + 1, 0), curr(m + 1, 0);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s[i - 1] == t[j - 1])
curr[j] = 1 + prev[j - 1];
else
curr[j] = max(prev[j], curr[j - 1]);
}
swap(prev, curr);
}
return prev[m];
}
// N=5000, M=5000: ~40 KB (100 MB → 40 KB!)
fn lcs_optimized(s: &str, t: &str) -> usize {
let (n, m) = (s.len(), t.len());
let s = s.as_bytes();
let t = t.as_bytes();
let mut prev = vec![0; m + 1];
let mut curr = vec![0; m + 1];
for i in 1..=n {
for j in 1..=m {
curr[j] = if s[i - 1] == t[j - 1] {
1 + prev[j - 1]
} else {
prev[j].max(curr[j - 1])
};
}
std::mem::swap(&mut prev, &mut curr);
}
prev[m]
}
💡 Always minimise memory when practical
Many contest problems have memory limits of 64–256 MB. A 5000×5000 int
table is ~100 MB — dangerously close. The two-row version is ~40 KB.
The pattern generalises: if dp[i] depends only on dp[i-1],
you can roll.