Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

[pull] master from TheAlgorithms:master #195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
* [Maximal Square](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/maximal_square.rs)
* [Maximum Subarray](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/maximum_subarray.rs)
* [Minimum Cost Path](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/minimum_cost_path.rs)
* [Optimal Bst](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/optimal_bst.rs)
* [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)
Expand Down
2 changes: 2 additions & 0 deletions src/dynamic_programming/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod matrix_chain_multiply;
mod maximal_square;
mod maximum_subarray;
mod minimum_cost_path;
mod optimal_bst;
mod rod_cutting;
mod snail;
mod subset_generation;
Expand Down Expand Up @@ -40,6 +41,7 @@ pub use self::matrix_chain_multiply::matrix_chain_multiply;
pub use self::maximal_square::maximal_square;
pub use self::maximum_subarray::maximum_subarray;
pub use self::minimum_cost_path::minimum_cost_path;
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;
Expand Down
93 changes: 93 additions & 0 deletions src/dynamic_programming/optimal_bst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Optimal Binary Search Tree Algorithm in Rust
// Time Complexity: O(n^3) with prefix sum optimization
// Space Complexity: O(n^2) for the dp table and prefix sum array

/// Constructs an Optimal Binary Search Tree from a list of key frequencies.
/// The goal is to minimize the expected search cost given key access frequencies.
///
/// # Arguments
/// * `freq` - A slice of integers representing the frequency of key access
///
/// # Returns
/// * An integer representing the minimum cost of the optimal BST
pub fn optimal_search_tree(freq: &[i32]) -> i32 {
let n = freq.len();
if n == 0 {
return 0;
}

// dp[i][j] stores the cost of optimal BST that can be formed from keys[i..=j]
let mut dp = vec![vec![0; n]; n];

// prefix_sum[i] stores sum of freq[0..i]
let mut prefix_sum = vec![0; n + 1];
for i in 0..n {
prefix_sum[i + 1] = prefix_sum[i] + freq[i];
}

// Base case: Trees with only one key
for i in 0..n {
dp[i][i] = freq[i];
}

// Build chains of increasing length l (from 2 to n)
for l in 2..=n {
for i in 0..=n - l {
let j = i + l - 1;
dp[i][j] = i32::MAX;

// Compute the total frequency sum in the range [i..=j] using prefix sum
let fsum = prefix_sum[j + 1] - prefix_sum[i];

// Try making each key in freq[i..=j] the root of the tree
for r in i..=j {
// Cost of left subtree
let left = if r > i { dp[i][r - 1] } else { 0 };
// Cost of right subtree
let right = if r < j { dp[r + 1][j] } else { 0 };

// Total cost = left + right + sum of frequencies (fsum)
let cost = left + right + fsum;

// Choose the minimum among all possible roots
if cost < dp[i][j] {
dp[i][j] = cost;
}
}
}
}

// Minimum cost of the optimal BST storing all keys
dp[0][n - 1]
}

#[cfg(test)]
mod tests {
use super::*;

// Macro to generate multiple test cases for the optimal_search_tree function
macro_rules! optimal_bst_tests {
($($name:ident: $input:expr => $expected:expr,)*) => {
$(
#[test]
fn $name() {
let freq = $input;
assert_eq!(optimal_search_tree(freq), $expected);
}
)*
};
}

optimal_bst_tests! {
// Common test cases
test_case_1: &[34, 10, 8, 50] => 180,
test_case_2: &[10, 12] => 32,
test_case_3: &[10, 12, 20] => 72,
test_case_4: &[25, 10, 20] => 95,
test_case_5: &[4, 2, 6, 3] => 26,

// Edge test cases
test_case_single: &[42] => 42,
test_case_empty: &[] => 0,
}
}