ExamplesBy LevelBy TopicLearning Paths
798 Fundamental

798-kadane-max-subarray — Kadane's Algorithm

Functional Programming

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

  • • Understand Kadane's insight: at each position, either extend the current subarray or start a new one
  • • Implement max_subarray(arr) -> i32 with O(n) time and O(1) space
  • • Track start and end indices with max_subarray_indices for reconstruction
  • • Handle all-negative arrays (maximum subarray is the least-negative element)
  • • Extend to the 2D case (maximum sum submatrix) using Kadane's on column prefix sums
  • Code 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

  • Functional elegance: OCaml's fold_left expresses Kadane's as a single combinator; Rust's explicit loop is more readable for the index-tracking variant.
  • All-negative case: Both languages return the maximum single element for all-negative arrays; the algorithm handles this naturally.
  • 2D extension: Both languages implement the 2D variant by fixing left and right column boundaries and running Kadane's on the row-sum array.
  • Applications: The 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);
        }
    }
    ✓ Tests Rust test suite
    #[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

    AspectOCamlRust
    Type systemHindley-MilnerOwnership + traits
    MemoryGCZero-cost abstractions
    MutabilityExplicit refmut keyword
    Error handlingOption/ResultResult<T, E>

    See README.md for detailed comparison.

    Exercises

  • Implement max_submatrix(matrix: &[Vec<i32>]) -> i32 using the column-compression + Kadane's technique to find the maximum sum submatrix in O(n² × m) time.
  • Implement max_circular_subarray(arr: &[i32]) -> i32 for circular arrays using the observation that max(normal, total - min_subarray) handles the wrap-around case.
  • Implement k_max_nonoverlapping_subarrays(arr, k) that finds the top k non-overlapping maximum sum subarrays using a DP extension of Kadane's.
  • Open Source Repos