From 1ce9f3a71a19f933a2b02929b6cd1c059dea007f Mon Sep 17 00:00:00 2001 From: Ali Alimohammadi <41567902+alialimohammadi@users.noreply.github.com> Date: 2025年11月28日 01:23:46 -0800 Subject: [PATCH] Add subset sum algorithm (#956) --- DIRECTORY.md | 1 + src/dynamic_programming/mod.rs | 2 + src/dynamic_programming/subset_sum.rs | 81 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/dynamic_programming/subset_sum.rs diff --git a/DIRECTORY.md b/DIRECTORY.md index 46bb2a3af9f..e6a35c9e71b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -105,6 +105,7 @@ * [Rod Cutting](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/rod_cutting.rs) * [Snail](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/snail.rs) * [Subset Generation](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/subset_generation.rs) + * [Subset Sum](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/subset_sum.rs) * [Trapped Rainwater](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/trapped_rainwater.rs) * [Word Break](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/word_break.rs) * Financial diff --git a/src/dynamic_programming/mod.rs b/src/dynamic_programming/mod.rs index f18c1847479..2d350c6a1d2 100644 --- a/src/dynamic_programming/mod.rs +++ b/src/dynamic_programming/mod.rs @@ -16,6 +16,7 @@ mod optimal_bst; mod rod_cutting; mod snail; mod subset_generation; +mod subset_sum; mod trapped_rainwater; mod word_break; @@ -45,5 +46,6 @@ pub use self::optimal_bst::optimal_search_tree; pub use self::rod_cutting::rod_cut; pub use self::snail::snail; pub use self::subset_generation::list_subset; +pub use self::subset_sum::is_sum_subset; pub use self::trapped_rainwater::trapped_rainwater; pub use self::word_break::word_break; diff --git a/src/dynamic_programming/subset_sum.rs b/src/dynamic_programming/subset_sum.rs new file mode 100644 index 00000000000..dfe0e809adc --- /dev/null +++ b/src/dynamic_programming/subset_sum.rs @@ -0,0 +1,81 @@ +//! This module provides a solution to the subset sum problem using dynamic programming. +//! +//! # Complexity +//! - Time complexity: O(n * sum) where n is array length and sum is the target sum +//! - Space complexity: O(n * sum) for the DP table +/// Determines if there exists a subset of the given array that sums to the target value. +/// Uses dynamic programming to solve the subset sum problem. +/// +/// # Arguments +/// * `arr` - A slice of integers representing the input array. +/// * `required_sum` - The target sum to check for. +/// +/// # Returns +/// * `bool` - A boolean indicating whether a subset exists that sums to the target. +pub fn is_sum_subset(arr: &[i32], required_sum: i32) -> bool { + let n = arr.len(); + + // Handle edge case where required sum is 0 (empty subset always sums to 0) + if required_sum == 0 { + return true; + } + + // Handle edge case where array is empty but required sum is positive + if n == 0 && required_sum> 0 { + return false; + } + // dp[i][j] stores whether sum j can be achieved using first i elements + let mut dp = vec![vec![false; required_sum as usize + 1]; n + 1]; + // Base case: sum 0 can always be achieved with any number of elements (empty subset) + for i in 0..=n { + dp[i][0] = true; + } + // Base case: with 0 elements, no positive sum can be achieved + for j in 1..=required_sum as usize { + dp[0][j] = false; + } + // Fill the DP table + for i in 1..=n { + for j in 1..=required_sum as usize { + if arr[i - 1]> j as i32 { + // Current element is too large, exclude it + dp[i][j] = dp[i - 1][j]; + } else { + // Either exclude the current element or include it + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - arr[i - 1] as usize]; + } + } + } + dp[n][required_sum as usize] +} +#[cfg(test)] +mod tests { + use super::*; + // Macro to generate multiple test cases for the is_sum_subset function + macro_rules! subset_sum_tests { + ($($name:ident: $input:expr => $expected:expr,)*) => { + $( + #[test] + fn $name() { + let (arr, sum) = $input; + assert_eq!(is_sum_subset(arr, sum), $expected); + } + )* + }; + } + subset_sum_tests! { + // Common test cases + test_case_1: (&[2, 4, 6, 8], 5) => false, + test_case_2: (&[2, 4, 6, 8], 14) => true, + test_case_3: (&[3, 34, 4, 12, 5, 2], 9) => true, + test_case_4: (&[3, 34, 4, 12, 5, 2], 30) => false, + test_case_5: (&[1, 2, 3, 4, 5], 15) => true, + + // Edge test cases + test_case_empty_array_positive_sum: (&[], 5) => false, + test_case_empty_array_zero_sum: (&[], 0) => true, + test_case_zero_sum: (&[1, 2, 3], 0) => true, + test_case_single_element_match: (&[5], 5) => true, + test_case_single_element_no_match: (&[3], 5) => false, + } +}