From af80ca6ca411c0df53fd51a0a55419bed6470a79 Mon Sep 17 00:00:00 2001 From: jtr109 Date: Wed, 19 Aug 2020 17:09:04 +0800 Subject: [PATCH 1/4] add test --- Cargo.lock | 4 ++++ Cargo.toml | 1 + README.md | 1 + edit_distance/Cargo.toml | 9 ++++++++ edit_distance/src/lib.rs | 47 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 edit_distance/Cargo.toml create mode 100644 edit_distance/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 4f75e37..9e49a6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,10 @@ name = "binary_tree_postorder_traversal" version = "0.1.0" +[[package]] +name = "edit_distance" +version = "0.1.0" + [[package]] name = "implement_queue_using_stacks" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9eb1a88..f5961ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ members = [ "intersection_of_two_arrays", "longest_palindromic_substring", "reverse_words_in_a_string_iii", + "edit_distance", ] diff --git a/README.md b/README.md index d0e4792..ce9b0c4 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Resolving problems of LeetCode in RustLang. * [5. Longest Palindromic Substring](./longest_palindromic_substring/lib.rs) * [7. Reverse Integer](./reverse_integer/src/lib.rs) * [15. 3 Sum](./three_sum/src/lib.rs) +* [72. Edit Distance](./edit_distance/src/lib.rs) * [88. Merge Sorted Array](./merge_sorted_array/src/lib.rs) * [145. Binary Tree Postorder Traversal](./binary_tree_postorder_traversal/src/lib.rs) * [215. Kth Largest Element in an Array](./kth_largest/src/lib.rs) diff --git a/edit_distance/Cargo.toml b/edit_distance/Cargo.toml new file mode 100644 index 0000000..dec118e --- /dev/null +++ b/edit_distance/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "edit_distance" +version = "0.1.0" +authors = ["Ryan Li "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/edit_distance/src/lib.rs b/edit_distance/src/lib.rs new file mode 100644 index 0000000..6943de4 --- /dev/null +++ b/edit_distance/src/lib.rs @@ -0,0 +1,47 @@ +/*! + * # 72. Edit Distance + * + * [Problem link](https://leetcode.com/problems/edit-distance/) + */ + +#![allow(dead_code)] + +struct Solution {} + +// ---------------------------------------------------------------------------- + +impl Solution { + pub fn min_distance(word1: String, word2: String) -> i32 { + 3 + } +} + +// ---------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + + fn accept(word1: &str, word2: &str, expected: i32) { + assert_eq!( + Solution::min_distance(word1.to_string(), word2.to_string()), + expected + ); + } + + #[test] + fn test_example_1() { + let word1 = "horse"; + let word2 = "ros"; + let expected = 3; + accept(word1, word2, expected); + } + + #[test] + fn test_example_2() { + let word1 = "intention"; + let word2 = "execution"; + let expected = 5; + accept(word1, word2, expected); + } +} From 6978cd354c37051c48336a3214ef503ae22fed8c Mon Sep 17 00:00:00 2001 From: jtr109 Date: Wed, 19 Aug 2020 17:55:29 +0800 Subject: [PATCH 2/4] add solution --- edit_distance/src/lib.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/edit_distance/src/lib.rs b/edit_distance/src/lib.rs index 6943de4..986c026 100644 --- a/edit_distance/src/lib.rs +++ b/edit_distance/src/lib.rs @@ -12,7 +12,21 @@ struct Solution {} impl Solution { pub fn min_distance(word1: String, word2: String) -> i32 { - 3 + if word1.len() == 0 { + return word2.len() as i32; + } + if word2.len() == 0 { + return word1.len() as i32; + } + let w1 = word1[1..].to_string(); + let w2 = word2[1..].to_string(); + if word1.chars().next().unwrap() == word2.chars().next().unwrap() { + return Solution::min_distance(w1.clone(), w2.clone()); + } + let insert = 1 + Solution::min_distance(word1.clone(), w2.clone()); // insert the first char of word2 in front of word1 + let delete = 1 + Solution::min_distance(w1.clone(), word2.clone()); // delete the first char of word1 + let edit = 1 + Solution::min_distance(w1.clone(), w2.clone()); // change from the first char of word1 to the one of word2 + *[insert, delete, edit].iter().min().unwrap() } } From 591a0140c9148aa3d0bd863192b5f44cd5347849 Mon Sep 17 00:00:00 2001 From: jtr109 Date: Wed, 26 Aug 2020 15:53:24 +0800 Subject: [PATCH 3/4] feat: add cache --- edit_distance/src/lib.rs | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/edit_distance/src/lib.rs b/edit_distance/src/lib.rs index 986c026..e6775c3 100644 --- a/edit_distance/src/lib.rs +++ b/edit_distance/src/lib.rs @@ -10,23 +10,37 @@ struct Solution {} // ---------------------------------------------------------------------------- +use std::collections::HashMap; + impl Solution { - pub fn min_distance(word1: String, word2: String) -> i32 { - if word1.len() == 0 { - return word2.len() as i32; - } - if word2.len() == 0 { - return word1.len() as i32; + pub fn reduce_min_distance( + word1: String, + word2: String, + cache: &mut HashMap<(String, String), usize>, + ) -> usize { + let (length1, length2) = (word1.len(), word2.len()); + if length1 == 0 || length2 == 0 { + let min = length1.max(length2); + cache.insert((word1.clone(), word2.clone()), min); + return min; } - let w1 = word1[1..].to_string(); - let w2 = word2[1..].to_string(); + let word1_slice = word1[1..].to_string(); + let word2_slice = word2[1..].to_string(); if word1.chars().next().unwrap() == word2.chars().next().unwrap() { - return Solution::min_distance(w1.clone(), w2.clone()); + return Solution::reduce_min_distance(word1_slice.clone(), word2_slice.clone(), cache); } - let insert = 1 + Solution::min_distance(word1.clone(), w2.clone()); // insert the first char of word2 in front of word1 - let delete = 1 + Solution::min_distance(w1.clone(), word2.clone()); // delete the first char of word1 - let edit = 1 + Solution::min_distance(w1.clone(), w2.clone()); // change from the first char of word1 to the one of word2 - *[insert, delete, edit].iter().min().unwrap() + let insert = 1 + Solution::reduce_min_distance(word1.clone(), word2_slice.clone(), cache); // insert the first char of word2 in front of word1 + let delete = 1 + Solution::reduce_min_distance(word1_slice.clone(), word2.clone(), cache); // delete the first char of word1 + let edit = + 1 + Solution::reduce_min_distance(word1_slice.clone(), word2_slice.clone(), cache); // change from the first char of word1 to the one of word2 + let min = *[insert, delete, edit].iter().min().unwrap(); + cache.insert((word1.clone(), word2.clone()), min); + min + } + + pub fn min_distance(word1: String, word2: String) -> i32 { + let mut cache = HashMap::new(); + Self::reduce_min_distance(word1, word2, &mut cache) as i32 } } From 7e5ef625d5bf519ae6e8cb2c82ad98af24144bd6 Mon Sep 17 00:00:00 2001 From: jtr109 Date: Wed, 26 Aug 2020 16:01:31 +0800 Subject: [PATCH 4/4] feat: use cache --- edit_distance/src/lib.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/edit_distance/src/lib.rs b/edit_distance/src/lib.rs index e6775c3..7dcee63 100644 --- a/edit_distance/src/lib.rs +++ b/edit_distance/src/lib.rs @@ -14,33 +14,35 @@ use std::collections::HashMap; impl Solution { pub fn reduce_min_distance( - word1: String, - word2: String, + word1: &str, + word2: &str, cache: &mut HashMap<(String, String), usize>, ) -> usize { + if let Some(&min) = cache.get(&(word1.to_string(), word2.to_string())) { + return min; + }; let (length1, length2) = (word1.len(), word2.len()); if length1 == 0 || length2 == 0 { let min = length1.max(length2); - cache.insert((word1.clone(), word2.clone()), min); + cache.insert((word1.to_string(), word2.to_string()), min); return min; } let word1_slice = word1[1..].to_string(); let word2_slice = word2[1..].to_string(); if word1.chars().next().unwrap() == word2.chars().next().unwrap() { - return Solution::reduce_min_distance(word1_slice.clone(), word2_slice.clone(), cache); + return Solution::reduce_min_distance(&word1_slice, &word2_slice, cache); } - let insert = 1 + Solution::reduce_min_distance(word1.clone(), word2_slice.clone(), cache); // insert the first char of word2 in front of word1 - let delete = 1 + Solution::reduce_min_distance(word1_slice.clone(), word2.clone(), cache); // delete the first char of word1 - let edit = - 1 + Solution::reduce_min_distance(word1_slice.clone(), word2_slice.clone(), cache); // change from the first char of word1 to the one of word2 + let insert = 1 + Solution::reduce_min_distance(word1, &word2_slice, cache); // insert the first char of word2 in front of word1 + let delete = 1 + Solution::reduce_min_distance(&word1_slice, word2, cache); // delete the first char of word1 + let edit = 1 + Solution::reduce_min_distance(&word1_slice, &word2_slice, cache); // change from the first char of word1 to the one of word2 let min = *[insert, delete, edit].iter().min().unwrap(); - cache.insert((word1.clone(), word2.clone()), min); + cache.insert((word1.to_string(), word2.to_string()), min); min } pub fn min_distance(word1: String, word2: String) -> i32 { let mut cache = HashMap::new(); - Self::reduce_min_distance(word1, word2, &mut cache) as i32 + Self::reduce_min_distance(&word1, &word2, &mut cache) as i32 } }