798-kadane-max-subarray — Kadane's Algorithm
Tutorial Video
Text description (accessibility)
This video demonstrates the "798-kadane-max-subarray — Kadane's Algorithm" functional Rust example. Difficulty level: Fundamental. Key concepts covered: Functional Programming. Maximum subarray sum (Kadane's algorithm, 1984) finds the contiguous subarray with the largest sum in O(n) time. Key difference from OCaml: 1. **Functional elegance**: OCaml's `fold_left` expresses Kadane's as a single combinator; Rust's explicit loop is more readable for the index
Tutorial
The Problem
Maximum subarray sum (Kadane's algorithm, 1984) finds the contiguous subarray with the largest sum in O(n) time. This is an astonishing result: intuitively it seems you must check all pairs, but a single pass suffices. It models maximum profit from a sequence of daily stock gains/losses, maximum signal amplitude in signal processing, and appears in image processing (maximum sum submatrix). It is one of the most elegant DP algorithms.
🎯 Learning Outcomes
max_subarray(arr) -> i32 with O(n) time and O(1) spacemax_subarray_indices for reconstructionCode Example
#![allow(clippy::all)]
//! # Kadane's Algorithm
pub fn max_subarray(arr: &[i32]) -> i32 {
if arr.is_empty() {
return 0;
}
let (mut max_so_far, mut max_ending) = (arr[0], arr[0]);
for &x in &arr[1..] {
max_ending = x.max(max_ending + x);
max_so_far = max_so_far.max(max_ending);
}
max_so_far
}
pub fn max_subarray_indices(arr: &[i32]) -> (i32, usize, usize) {
if arr.is_empty() {
return (0, 0, 0);
}
let (mut max_so_far, mut max_ending) = (arr[0], arr[0]);
let (mut start, mut end, mut s) = (0, 0, 0);
for i in 1..arr.len() {
if arr[i] > max_ending + arr[i] {
max_ending = arr[i];
s = i;
} else {
max_ending += arr[i];
}
if max_ending > max_so_far {
max_so_far = max_ending;
start = s;
end = i;
}
}
(max_so_far, start, end)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_kadane() {
assert_eq!(max_subarray(&[-2, 1, -3, 4, -1, 2, 1, -5, 4]), 6);
}
}Key Differences
fold_left expresses Kadane's as a single combinator; Rust's explicit loop is more readable for the index-tracking variant.max_subarray pattern appears in financial (buy-low-sell-high when returns are daily differences), signal processing, and machine learning (max activation windows).OCaml Approach
OCaml implements Kadane's with a fold_left over the array, carrying (max_so_far, max_ending) as the accumulator: Array.fold_left (fun (best, cur) x -> let cur' = max x (cur + x) in (max best cur', cur')) (arr.(0), arr.(0)) arr. This functional one-liner is idiomatic OCaml. The index-tracking variant requires imperative state with ref cells.
Full Source
#![allow(clippy::all)]
//! # Kadane's Algorithm
pub fn max_subarray(arr: &[i32]) -> i32 {
if arr.is_empty() {
return 0;
}
let (mut max_so_far, mut max_ending) = (arr[0], arr[0]);
for &x in &arr[1..] {
max_ending = x.max(max_ending + x);
max_so_far = max_so_far.max(max_ending);
}
max_so_far
}
pub fn max_subarray_indices(arr: &[i32]) -> (i32, usize, usize) {
if arr.is_empty() {
return (0, 0, 0);
}
let (mut max_so_far, mut max_ending) = (arr[0], arr[0]);
let (mut start, mut end, mut s) = (0, 0, 0);
for i in 1..arr.len() {
if arr[i] > max_ending + arr[i] {
max_ending = arr[i];
s = i;
} else {
max_ending += arr[i];
}
if max_ending > max_so_far {
max_so_far = max_ending;
start = s;
end = i;
}
}
(max_so_far, start, end)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_kadane() {
assert_eq!(max_subarray(&[-2, 1, -3, 4, -1, 2, 1, -5, 4]), 6);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_kadane() {
assert_eq!(max_subarray(&[-2, 1, -3, 4, -1, 2, 1, -5, 4]), 6);
}
}
Deep Comparison
OCaml vs Rust: Kadane Max Subarray
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
max_submatrix(matrix: &[Vec<i32>]) -> i32 using the column-compression + Kadane's technique to find the maximum sum submatrix in O(n² × m) time.max_circular_subarray(arr: &[i32]) -> i32 for circular arrays using the observation that max(normal, total - min_subarray) handles the wrap-around case.k_max_nonoverlapping_subarrays(arr, k) that finds the top k non-overlapping maximum sum subarrays using a DP extension of Kadane's.