diff --git a/README.md b/README.md index 11992fc..643374a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The `ladderz` project is a collection of math and tech concepts implemented in c - **[`lz` CLI](https://rzmk.github.io/ladderz/lz/index.html)** - A command line tool for running ladderz functions - **[notebooks](notebooks)** - Rust & Python Jupyter notebooks with concept exercises and solutions -> If you're looking for a more efficient implementation of a concept (e.g., for use in your programs), other resources may be more useful. +> Note: If you're looking for a more efficient implementation of a concept (e.g., for use in your programs), other resources may be more useful. ## Demos diff --git a/ladderz/src/dsa.rs b/ladderz/src/dsa.rs index fd8c576..36e50a1 100644 --- a/ladderz/src/dsa.rs +++ b/ladderz/src/dsa.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; pub fn contains_duplicate(nums: Vec) -> bool { let mut seen = HashSet::::new(); @@ -11,6 +11,49 @@ pub fn contains_duplicate(nums: Vec) -> bool { false } +pub fn is_anagram(a: String, b: String) -> bool { + let mut letters = HashMap::new(); + for c in a.chars() { + if let Some(&value) = letters.get(&c) { + letters.insert(c, value + 1); + } else { + letters.insert(c, 1); + } + } + for c in b.chars() { + if let Some(&value) = letters.get(&c) { + if value - 1 < 0 { + return false; + } + letters.insert(c, value - 1); + } else { + return false; + } + } + for (_, &count) in letters.iter() { + if count > 0 { + return false; + } + } + true +} + +pub fn is_anagram2(a: String, b: String) -> bool { + if a.len() != b.len() { + return false; + } + + let mut letters = HashMap::new(); + for c in a.chars() { + *letters.entry(c).or_default() += 1; + } + for c in b.chars() { + *letters.entry(c).or_default() -= 1; + } + + letters.into_values().all(|c: i32| c == 0) +} + #[cfg(test)] mod tests { use super::*; @@ -21,4 +64,11 @@ mod tests { let expected = true; assert_eq!(result, expected); } + + #[test] + fn test_is_anagram() { + let result = is_anagram("marc".to_owned(), "cram".to_owned()); + let expected = true; + assert_eq!(result, expected); + } } diff --git a/lz/src/dsa.rs b/lz/src/dsa.rs index 60856b4..a494045 100644 --- a/lz/src/dsa.rs +++ b/lz/src/dsa.rs @@ -34,6 +34,36 @@ pub enum Dsa { #[arg(short = 'r', long)] raw: bool, }, + /// Returns true or false based on whether string a is an anagram of string b. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz dsa is-anagram marc cram + /// ``` + /// + /// ### Output + /// + /// ```bash + /// "marc" is an anagram of "cram". + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// true + /// ``` + IsAnagram { + /// The first string to compare against. + a: String, + /// The second string to compare against. + b: String, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, } pub fn match_dsa(function: Option) { @@ -50,6 +80,18 @@ pub fn match_dsa(function: Option) { ) } }, + Some(Dsa::IsAnagram { a, b, raw }) => match raw { + true => println!("{:?}", is_anagram(a, b)), + false => { + let result = is_anagram(a.clone(), b.clone()); + println!( + "{:?} {} an anagram of {:?}.", + a, + if result { "is" } else { "is not" }, + b, + ) + } + }, None => { println!("Please provide a function to use."); } diff --git a/notebooks/rust/dsa.ipynb b/notebooks/rust/dsa.ipynb index 7541320..1c798af 100644 --- a/notebooks/rust/dsa.ipynb +++ b/notebooks/rust/dsa.ipynb @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "metadata": { "vscode": { "languageId": "rust" @@ -50,7 +50,7 @@ "true" ] }, - "execution_count": 6, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -58,6 +58,37 @@ "source": [ "dsa::contains_duplicate(vec![1, 3, 4, 2, 4])" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 242. Valid Anagram" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "vscode": { + "languageId": "rust" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "true" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dsa::is_anagram(\"marc\".to_owned(), \"cram\".to_owned())" + ] } ], "metadata": {