795-subset-sum-dp — Subset Sum
Tutorial Video
Text description (accessibility)
This video demonstrates the "795-subset-sum-dp — Subset Sum" functional Rust example. Difficulty level: Advanced. Key concepts covered: Functional Programming. Subset sum asks: can a subset of given numbers sum to a target value? Key difference from OCaml: 1. **Right
Tutorial
The Problem
Subset sum asks: can a subset of given numbers sum to a target value? It is NP-complete in general but solvable in pseudo-polynomial O(n × target) time via DP. It underlies the 0/1 knapsack problem, is used in cryptography (merkle-hellman knapsack), and appears in scheduling (can a set of tasks exactly fill a time slot?) and partitioning problems (can employees be split into equal-salary teams?).
🎯 Learning Outcomes
dp[w] = whether sum w is achievabledp[i] = dp[i] || dp[i - num]count_subsets(nums, target) for counting the number of valid subsetsCode Example
#![allow(clippy::all)]
//! # Subset Sum
pub fn subset_sum(nums: &[i32], target: i32) -> bool {
if target < 0 {
return false;
}
let t = target as usize;
let mut dp = vec![false; t + 1];
dp[0] = true;
for &n in nums {
if n < 0 {
continue;
}
let n = n as usize;
for i in (n..=t).rev() {
dp[i] = dp[i] || dp[i - n];
}
}
dp[t]
}
pub fn count_subsets(nums: &[usize], target: usize) -> usize {
let mut dp = vec![0usize; target + 1];
dp[0] = 1;
for &n in nums {
for i in (n..=target).rev() {
dp[i] += dp[i - n];
}
}
dp[target]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subset() {
assert!(subset_sum(&[3, 34, 4, 12, 5, 2], 9));
}
#[test]
fn test_count() {
assert_eq!(count_subsets(&[1, 2, 3], 4), 1);
}
}Key Differences
OCaml Approach
OCaml implements with Array.make (t+1) false. The right-to-left iteration: for i = t downto n do dp.(i) <- dp.(i) || dp.(i-n) done. The counting variant uses int array. OCaml's Array.blit can copy and shift for the "extend with reversed order" optimization. The partition problem variant: subset_sum nums (sum/2) where sum = List.fold_left (+) 0 nums.
Full Source
#![allow(clippy::all)]
//! # Subset Sum
pub fn subset_sum(nums: &[i32], target: i32) -> bool {
if target < 0 {
return false;
}
let t = target as usize;
let mut dp = vec![false; t + 1];
dp[0] = true;
for &n in nums {
if n < 0 {
continue;
}
let n = n as usize;
for i in (n..=t).rev() {
dp[i] = dp[i] || dp[i - n];
}
}
dp[t]
}
pub fn count_subsets(nums: &[usize], target: usize) -> usize {
let mut dp = vec![0usize; target + 1];
dp[0] = 1;
for &n in nums {
for i in (n..=target).rev() {
dp[i] += dp[i - n];
}
}
dp[target]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subset() {
assert!(subset_sum(&[3, 34, 4, 12, 5, 2], 9));
}
#[test]
fn test_count() {
assert_eq!(count_subsets(&[1, 2, 3], 4), 1);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subset() {
assert!(subset_sum(&[3, 34, 4, 12, 5, 2], 9));
}
#[test]
fn test_count() {
assert_eq!(count_subsets(&[1, 2, 3], 4), 1);
}
}
Deep Comparison
OCaml vs Rust: Subset Sum Dp
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
partition_equal(nums: &[i32]) -> bool using subset sum: check if the total sum is even and if sum/2 is achievable.multi_subset_sum(nums, targets: &[i32]) -> Vec<bool> that answers multiple target queries in one pass using the same DP table.