Browse Source

feat: word_break2

Zhang Li 1 year ago
parent
commit
1be62d6477
2 changed files with 111 additions and 1 deletions
  1. 2 1
      src/solutions/dp/mod.rs
  2. 109 0
      src/solutions/dp/word_break2.rs

+ 2 - 1
src/solutions/dp/mod.rs

@@ -17,4 +17,5 @@ mod best_time_to_buy_and_sell_stock3;
 mod palindrome_partitioning;
 mod palindrome_partitioning2;
 mod candy;
-mod word_break;
+mod word_break;
+mod word_break2;

+ 109 - 0
src/solutions/dp/word_break2.rs

@@ -0,0 +1,109 @@
+struct Solution;
+
+use std::collections::HashSet;
+
+impl Solution {
+    pub fn word_break(s: String, word_dict: Vec<String>) -> Vec<String> {
+        let mut min_length = usize::MAX;
+        let mut max_length = 0;
+        let mut word_dict_2 = HashSet::new();
+        for w in word_dict {
+            let l = w.len();
+            if l < min_length { min_length = l; }
+            if l > max_length { max_length = l; }
+            word_dict_2.insert(w);
+        }
+
+        let dp = Solution::valid_wb(s.clone(), &word_dict_2, s.len(), min_length);
+        // println!("dp: {:?}", dp);
+
+        let mut res = vec![];
+        let mut cur = vec![];
+        if dp[0][s.len()-1] {
+            Solution::helper(s.clone(), &dp, s.len(), 0, &mut cur, &mut res, &word_dict_2);
+        }
+
+        res
+
+    }
+
+    fn helper(s: String, dp: &Vec<Vec<bool>>, n: usize, idx: usize, cur: &mut Vec<String>, res: &mut Vec<String>, word_dict: &HashSet<String>) {
+        if idx == n {
+            res.push(cur.join(" "));
+            return;
+        }
+
+        for i in idx..n {
+            if !dp[idx][i] { continue; }
+            if word_dict.contains(&s[idx..i+1].to_string()) {
+                cur.push(s[idx..i+1].to_string());
+                Solution::helper(s.clone(), dp, n, i+1, cur, res, word_dict);
+                cur.pop();
+            }
+        }
+
+    }
+
+    fn valid_wb(s: String, word_dict: &HashSet<String>, n: usize, min_length: usize) -> Vec<Vec<bool>> {
+
+        let mut dp = vec![vec![false; n]; n];
+
+        for i in 0..n {
+            if word_dict.contains(&s[i..i+1].to_string()) {
+                dp[i][i] = true;
+            }
+        }
+
+        for l in 2..=n {
+            if l < min_length { continue; }
+            for i in 0..(n-l+1) {
+                let j = i + l - 1;
+
+                let end = j + 1;
+                if word_dict.contains(&s[i..end].to_string()) {
+                    dp[i][j] = true;
+                    continue;
+                }
+                for k in i..j {
+                    dp[i][j] = dp[i][j] ||  (dp[i][k] && dp[k+1][j]);
+                }
+            }
+        }
+
+        dp
+
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_word_break() {
+        let s = String::from("catsanddog");
+        let word_dict = vec![String::from("cats"), String::from("dog"), String::from("sand"), String::from("and"), String::from("cat")];
+        let res = Solution::word_break(s, word_dict);
+        let expect = vec![String::from("cat sand dog"),String::from("cats and dog")];
+        assert_eq!(res, expect);
+    }
+
+    #[test]
+    fn test_word_break2() {
+        let s = String::from("a");
+        let word_dict = vec![String::from("a")];
+        let res = Solution::word_break(s, word_dict);
+        let expect = vec![String::from("a")];
+        assert_eq!(res, expect);
+    }
+
+    #[test]
+    fn test_word_break3() {
+        let s = String::from("ab");
+        let word_dict = vec![String::from("a"), String::from("b")];
+        let res = Solution::word_break(s, word_dict);
+        let expect: Vec<String> = vec![String::from("a b")];
+        assert_eq!(res, expect);
+    }
+
+}