forked from TheAlgorithms/Rust
-
Notifications
You must be signed in to change notification settings - Fork 0
[pull] master from TheAlgorithms:master #223
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
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
src/bit_manipulation/binary_count_trailing_zeros.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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}" | ||
| ); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
src/dynamic_programming/palindrome_partitioning.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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: <https://www.youtube.com/watch?v=_H8V5hJUGd0> | ||
| pub fn minimum_palindrome_partitions(s: &str) -> usize { | ||
| let chars: Vec<char> = 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); | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.