From 5c4593cb825f251890fed27b5d3eb1d88cfb7e9d Mon Sep 17 00:00:00 2001 From: Ali Alimohammadi <41567902+alialimohammadi@users.noreply.github.com> Date: 2025年12月17日 13:02:49 -0800 Subject: [PATCH 1/2] feat: add Palindrome Partitioning algorithm (#971) --- DIRECTORY.md | 9 +- src/dynamic_programming/mod.rs | 2 + .../palindrome_partitioning.rs | 130 ++++++++++++++++++ 3 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 src/dynamic_programming/palindrome_partitioning.rs diff --git a/DIRECTORY.md b/DIRECTORY.md index 9645d01eda3..934db9477b6 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -110,6 +110,7 @@ * [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) + * [Palindrome Partitioning](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/palindrome_partitioning.rs) * [Rod Cutting](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/rod_cutting.rs) * [Smith-Waterman](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/smith_waterman.rs) * [Snail](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/snail.rs) @@ -150,7 +151,7 @@ * [Segment](https://github.com/TheAlgorithms/Rust/blob/master/src/geometry/segment.rs) * Graph * [Astar](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/astar.rs) - * [Bellman Ford](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/bellman_ford.rs) + * [Bellman-Ford](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/bellman_ford.rs) * [Bipartite Matching](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/bipartite_matching.rs) * [Breadth First Search](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/breadth_first_search.rs) * [Centroid Decomposition](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/centroid_decomposition.rs) @@ -233,12 +234,12 @@ * [Geometric Series](https://github.com/TheAlgorithms/Rust/blob/master/src/math/geometric_series.rs) * [Greatest Common Divisor](https://github.com/TheAlgorithms/Rust/blob/master/src/math/greatest_common_divisor.rs) * [Huber Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/math/huber_loss.rs) - * [Infix To Postfix](https://github.com/TheAlgorithms/Rust/blob/master/src/math/infix_to_postfix.rs) + * [Infix to Postfix](https://github.com/TheAlgorithms/Rust/blob/master/src/math/infix_to_postfix.rs) * [Interest](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interest.rs) * [Interpolation](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interpolation.rs) * [Interquartile Range](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interquartile_range.rs) * [Karatsuba Multiplication](https://github.com/TheAlgorithms/Rust/blob/master/src/math/karatsuba_multiplication.rs) - * [LCM Of N Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/lcm_of_n_numbers.rs) + * [LCM of N Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/lcm_of_n_numbers.rs) * [Leaky Relu](https://github.com/TheAlgorithms/Rust/blob/master/src/math/leaky_relu.rs) * [Least Square Approx](https://github.com/TheAlgorithms/Rust/blob/master/src/math/least_square_approx.rs) * [Linear Sieve](https://github.com/TheAlgorithms/Rust/blob/master/src/math/linear_sieve.rs) @@ -249,7 +250,7 @@ * [Miller Rabin](https://github.com/TheAlgorithms/Rust/blob/master/src/math/miller_rabin.rs) * [Modular Exponential](https://github.com/TheAlgorithms/Rust/blob/master/src/math/modular_exponential.rs) * [Newton Raphson](https://github.com/TheAlgorithms/Rust/blob/master/src/math/newton_raphson.rs) - * [Nthprime](https://github.com/TheAlgorithms/Rust/blob/master/src/math/nthprime.rs) + * [N-th prime](https://github.com/TheAlgorithms/Rust/blob/master/src/math/nthprime.rs) * [Pascal Triangle](https://github.com/TheAlgorithms/Rust/blob/master/src/math/pascal_triangle.rs) * [Perfect Cube](https://github.com/TheAlgorithms/Rust/blob/master/src/math/perfect_cube.rs) * [Perfect Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/perfect_numbers.rs) diff --git a/src/dynamic_programming/mod.rs b/src/dynamic_programming/mod.rs index b2d3c640f98..7f5de2be42c 100644 --- a/src/dynamic_programming/mod.rs +++ b/src/dynamic_programming/mod.rs @@ -14,6 +14,7 @@ mod maximal_square; mod maximum_subarray; mod minimum_cost_path; mod optimal_bst; +mod palindrome_partitioning; mod rod_cutting; mod smith_waterman; mod snail; @@ -47,6 +48,7 @@ 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::palindrome_partitioning::minimum_palindrome_partitions; pub use self::rod_cutting::rod_cut; pub use self::smith_waterman::{score_function, smith_waterman, traceback}; pub use self::snail::snail; diff --git a/src/dynamic_programming/palindrome_partitioning.rs b/src/dynamic_programming/palindrome_partitioning.rs new file mode 100644 index 00000000000..4b46bc3f895 --- /dev/null +++ b/src/dynamic_programming/palindrome_partitioning.rs @@ -0,0 +1,130 @@ +/// Finds the minimum cuts needed for a palindrome partitioning of a string +/// +/// Given a string s, partition s such that every substring of the partition is a palindrome. +/// This function returns the minimum number of cuts needed. +/// +/// Time Complexity: O(n^2) +/// Space Complexity: O(n^2) +/// +/// # Arguments +/// +/// * `s` - The input string to partition +/// +/// # Returns +/// +/// The minimum number of cuts needed +/// +/// # Examples +/// +/// ``` +/// use the_algorithms_rust::dynamic_programming::minimum_palindrome_partitions; +/// +/// assert_eq!(minimum_palindrome_partitions("aab"), 1); +/// assert_eq!(minimum_palindrome_partitions("aaa"), 0); +/// assert_eq!(minimum_palindrome_partitions("ababbbabbababa"), 3); +/// ``` +/// +/// # Algorithm Explanation +/// +/// The algorithm uses dynamic programming with two key data structures: +/// - `cut[i]`: minimum cuts needed for substring from index 0 to i +/// - `is_palindromic[j][i]`: whether substring from index j to i is a palindrome +/// +/// For each position i, we check all possible starting positions j to determine +/// if the substring s[j..=i] is a palindrome. If it is, we update the minimum +/// cut count accordingly. +/// +/// Reference: +pub fn minimum_palindrome_partitions(s: &str) -> usize { + let chars: Vec = s.chars().collect(); + let length = chars.len(); + + if length == 0 { + return 0; + } + + // cut[i] represents the minimum cuts needed for substring from 0 to i + let mut cut = vec![0; length]; + + // is_palindromic[j][i] represents whether substring from j to i is a palindrome + let mut is_palindromic = vec![vec![false; length]; length]; + + for i in 0..length { + let mut mincut = i; + + for j in 0..=i { + // Check if substring from j to i is a palindrome + // A substring is a palindrome if: + // 1. The characters at both ends match (chars[i] == chars[j]) + // 2. AND either: + // - The substring length is less than 2 (single char or two same chars) + // - OR the inner substring (j+1 to i-1) is also a palindrome + if chars[i] == chars[j] && (i - j < 2 || is_palindromic[j + 1][i - 1]) { + is_palindromic[j][i] = true; + mincut = if j == 0 { + // If the entire substring from 0 to i is a palindrome, no cuts needed + 0 + } else { + // Otherwise, take minimum of current mincut and (cuts up to j-1) + 1 + mincut.min(cut[j - 1] + 1) + }; + } + } + + cut[i] = mincut; + } + + cut[length - 1] +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_basic_cases() { + // "aab" -> "aa" | "b" = 1 cut + assert_eq!(minimum_palindrome_partitions("aab"), 1); + + // "aaa" is already a palindrome = 0 cuts + assert_eq!(minimum_palindrome_partitions("aaa"), 0); + + // Complex case + assert_eq!(minimum_palindrome_partitions("ababbbabbababa"), 3); + } + + #[test] + fn test_edge_cases() { + // Empty string + assert_eq!(minimum_palindrome_partitions(""), 0); + + // Single character is always a palindrome + assert_eq!(minimum_palindrome_partitions("a"), 0); + + // Two different characters need 1 cut + assert_eq!(minimum_palindrome_partitions("ab"), 1); + } + + #[test] + fn test_palindromes() { + // Already a palindrome + assert_eq!(minimum_palindrome_partitions("racecar"), 0); + assert_eq!(minimum_palindrome_partitions("noon"), 0); + assert_eq!(minimum_palindrome_partitions("abba"), 0); + } + + #[test] + fn test_non_palindromes() { + // All different characters need n-1 cuts + assert_eq!(minimum_palindrome_partitions("abcde"), 4); + + // Two pairs need 1 cut + assert_eq!(minimum_palindrome_partitions("aabb"), 1); + } + + #[test] + fn test_longer_strings() { + assert_eq!(minimum_palindrome_partitions("aaabaa"), 1); + assert_eq!(minimum_palindrome_partitions("abcbm"), 2); + } +} From 7a261d7c8e087acbc0662af8abeaf3ed03ab190a Mon Sep 17 00:00:00 2001 From: Ali Alimohammadi <41567902+alialimohammadi@users.noreply.github.com> Date: 2025年12月17日 14:04:27 -0800 Subject: [PATCH 2/2] feat: add binary count trailing zeros algorithm (#972) --- DIRECTORY.md | 1 + .../binary_count_trailing_zeros.rs | 119 ++++++++++++++++++ src/bit_manipulation/mod.rs | 2 + 3 files changed, 122 insertions(+) create mode 100644 src/bit_manipulation/binary_count_trailing_zeros.rs diff --git a/DIRECTORY.md b/DIRECTORY.md index 934db9477b6..1c08021c544 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -26,6 +26,7 @@ * [Reverse Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/reverse_bits.rs) * [Sum of Two Integers](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/sum_of_two_integers.rs) * [Swap Odd and Even Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/swap_odd_even_bits.rs) + * [Trailing Zeros](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/binary_count_trailing_zeros.rs) * [Two's Complement](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/twos_complement.rs) * Ciphers * [AES](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/aes.rs) diff --git a/src/bit_manipulation/binary_count_trailing_zeros.rs b/src/bit_manipulation/binary_count_trailing_zeros.rs new file mode 100644 index 00000000000..9950375ddf9 --- /dev/null +++ b/src/bit_manipulation/binary_count_trailing_zeros.rs @@ -0,0 +1,119 @@ +/// Counts the number of trailing zeros in the binary representation of a number +/// +/// # Arguments +/// +/// * `num` - The input number +/// +/// # Returns +/// +/// The number of trailing zeros in the binary representation +/// +/// # Examples +/// +/// ``` +/// use the_algorithms_rust::bit_manipulation::binary_count_trailing_zeros; +/// +/// assert_eq!(binary_count_trailing_zeros(25), 0); +/// assert_eq!(binary_count_trailing_zeros(36), 2); +/// assert_eq!(binary_count_trailing_zeros(16), 4); +/// assert_eq!(binary_count_trailing_zeros(58), 1); +/// ``` +pub fn binary_count_trailing_zeros(num: u64) -> u32 { + if num == 0 { + return 0; + } + num.trailing_zeros() +} + +/// Alternative implementation using bit manipulation +/// +/// Uses the bit manipulation trick: log2(num & -num) +/// +/// # Examples +/// +/// ``` +/// // This function uses bit manipulation: log2(num & -num) +/// // where num & -num isolates the rightmost set bit +/// # fn binary_count_trailing_zeros_bitwise(num: u64) -> u32 { +/// # if num == 0 { return 0; } +/// # let rightmost_set_bit = num & (num.wrapping_neg()); +/// # 63 - rightmost_set_bit.leading_zeros() +/// # } +/// assert_eq!(binary_count_trailing_zeros_bitwise(25), 0); +/// assert_eq!(binary_count_trailing_zeros_bitwise(36), 2); +/// assert_eq!(binary_count_trailing_zeros_bitwise(16), 4); +/// ``` +#[allow(dead_code)] +pub fn binary_count_trailing_zeros_bitwise(num: u64) -> u32 { + if num == 0 { + return 0; + } + + let rightmost_set_bit = num & (num.wrapping_neg()); + 63 - rightmost_set_bit.leading_zeros() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_basic_cases() { + assert_eq!(binary_count_trailing_zeros(25), 0); + assert_eq!(binary_count_trailing_zeros(36), 2); + assert_eq!(binary_count_trailing_zeros(16), 4); + assert_eq!(binary_count_trailing_zeros(58), 1); + assert_eq!(binary_count_trailing_zeros(4294967296), 32); + } + + #[test] + fn test_zero() { + assert_eq!(binary_count_trailing_zeros(0), 0); + } + + #[test] + fn test_powers_of_two() { + assert_eq!(binary_count_trailing_zeros(1), 0); + assert_eq!(binary_count_trailing_zeros(2), 1); + assert_eq!(binary_count_trailing_zeros(4), 2); + assert_eq!(binary_count_trailing_zeros(8), 3); + assert_eq!(binary_count_trailing_zeros(1024), 10); + } + + #[test] + fn test_bitwise_vs_builtin() { + // Test that bitwise implementation matches built-in trailing_zeros() + let test_cases = vec![ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 16, + 25, + 36, + 58, + 64, + 100, + 128, + 256, + 512, + 1024, + 4294967296, + u64::MAX - 1, + u64::MAX, + ]; + + for num in test_cases { + assert_eq!( + binary_count_trailing_zeros(num), + binary_count_trailing_zeros_bitwise(num), + "Mismatch for input: {num}" + ); + } + } +} diff --git a/src/bit_manipulation/mod.rs b/src/bit_manipulation/mod.rs index 95bbb755123..606dc81e89e 100644 --- a/src/bit_manipulation/mod.rs +++ b/src/bit_manipulation/mod.rs @@ -1,4 +1,5 @@ mod binary_coded_decimal; +mod binary_count_trailing_zeros; mod counting_bits; mod find_previous_power_of_two; mod highest_set_bit; @@ -10,6 +11,7 @@ mod swap_odd_even_bits; mod twos_complement; pub use self::binary_coded_decimal::binary_coded_decimal; +pub use self::binary_count_trailing_zeros::binary_count_trailing_zeros; pub use self::counting_bits::count_set_bits; pub use self::find_previous_power_of_two::find_previous_power_of_two; pub use self::highest_set_bit::find_highest_set_bit;

AltStyle によって変換されたページ (->オリジナル) /