|
@@ -0,0 +1,65 @@
|
|
|
|
+struct Solution;
|
|
|
|
+
|
|
|
|
+impl Solution {
|
|
|
|
+ pub fn ladder_length(begin_word: String, end_word: String, word_list: Vec<String>) -> i32 {
|
|
|
|
+
|
|
|
|
+ let mut queue = std::collections::VecDeque::new();
|
|
|
|
+ let mut visited = std::collections::HashSet::new();
|
|
|
|
+ queue.push_back((&begin_word, 1));
|
|
|
|
+
|
|
|
|
+ while let Some((src, idx)) = queue.pop_front() {
|
|
|
|
+ if end_word.eq(src) {
|
|
|
|
+ return idx;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if !visited.insert(src) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for word in &word_list {
|
|
|
|
+ if Solution::is_ladder_str(src.as_bytes(), word.as_bytes()) {
|
|
|
|
+ queue.push_back((word, idx + 1));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ 0
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn is_ladder_str(src: &[u8], dst: &[u8]) -> bool {
|
|
|
|
+ if src.len() != dst.len() {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let mut idx = 0;
|
|
|
|
+
|
|
|
|
+ for i in 0..src.len() {
|
|
|
|
+ if idx > 1 {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if src[i] != dst[i] {
|
|
|
|
+ idx += 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ idx == 1
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(test)]
|
|
|
|
+mod tests {
|
|
|
|
+ use super::*;
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn test_ladder_length() {
|
|
|
|
+ let begin_word = String::from("hit");
|
|
|
|
+ let end_word = String::from("cog");
|
|
|
|
+ let word_list = vec![String::from("hot"),String::from("dot"),String::from("dog"),String::from("lot"),String::from("log"),String::from("cog")];
|
|
|
|
+ let res = Solution::ladder_length(begin_word, end_word, word_list);
|
|
|
|
+ assert_eq!(res, 5);
|
|
|
|
+ }
|
|
|
|
+}
|