793-minimum-path-sum — Minimum Path Sum
Tutorial Video
Text description (accessibility)
This video demonstrates the "793-minimum-path-sum — Minimum Path Sum" functional Rust example. Difficulty level: Intermediate. Key concepts covered: Functional Programming. Finding the minimum-cost path through a grid from the top-left to the bottom-right (moving only right or down) is a fundamental 2D DP problem. Key difference from OCaml: 1. **In
Tutorial
The Problem
Finding the minimum-cost path through a grid from the top-left to the bottom-right (moving only right or down) is a fundamental 2D DP problem. It models route planning in robotics, game pathfinding with terrain costs, circuit board wiring, and is a building block for more complex grid DP problems. The constraint of only moving right or down makes it solvable in O(mn) with O(1) extra space (modifying the grid in place).
🎯 Learning Outcomes
dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])dp[m-1][n-1]Code Example
#![allow(clippy::all)]
//! # Minimum Path Sum
pub fn min_path_sum(grid: &[Vec<i32>]) -> i32 {
if grid.is_empty() || grid[0].is_empty() {
return 0;
}
let (m, n) = (grid.len(), grid[0].len());
let mut dp = vec![vec![0; n]; m];
dp[0][0] = grid[0][0];
for j in 1..n {
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
for i in 1..m {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for i in 1..m {
for j in 1..n {
dp[i][j] = grid[i][j] + dp[i - 1][j].min(dp[i][j - 1]);
}
}
dp[m - 1][n - 1]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_path() {
let grid = vec![vec![1, 3, 1], vec![1, 5, 1], vec![4, 2, 1]];
assert_eq!(min_path_sum(&grid), 7);
}
}Key Differences
OCaml Approach
OCaml implements with Array.make_matrix m n 0 and fills boundary conditions explicitly. The 2D iteration uses nested for loops. Functional style can use Array.init m (fun i -> Array.init n (fun j -> ...)) but requires careful ordering for dependency correctness. The OCaml min function and array access patterns are idiomatic.
Full Source
#![allow(clippy::all)]
//! # Minimum Path Sum
pub fn min_path_sum(grid: &[Vec<i32>]) -> i32 {
if grid.is_empty() || grid[0].is_empty() {
return 0;
}
let (m, n) = (grid.len(), grid[0].len());
let mut dp = vec![vec![0; n]; m];
dp[0][0] = grid[0][0];
for j in 1..n {
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
for i in 1..m {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for i in 1..m {
for j in 1..n {
dp[i][j] = grid[i][j] + dp[i - 1][j].min(dp[i][j - 1]);
}
}
dp[m - 1][n - 1]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_path() {
let grid = vec![vec![1, 3, 1], vec![1, 5, 1], vec![4, 2, 1]];
assert_eq!(min_path_sum(&grid), 7);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_path() {
let grid = vec![vec![1, 3, 1], vec![1, 5, 1], vec![4, 2, 1]];
assert_eq!(min_path_sum(&grid), 7);
}
}
Deep Comparison
OCaml vs Rust: Minimum Path Sum
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
min_path_sum_with_path(grid) -> (i32, Vec<(usize,usize)>) that returns both the minimum sum and the actual path as a list of coordinates.grid directly and uses O(1) extra space. Note any aliasing concerns.