1. 程式人生 > >【LeetCode & 劍指offer刷題】動態規劃與貪婪法題15:Word Break(系列)

【LeetCode & 劍指offer刷題】動態規劃與貪婪法題15:Word Break(系列)

【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...)

Word Break(系列)

Word Break Given a   non-empty   string   s   and a dictionary   wordDict   containing a list of   non-empty
  words, determine if   s   can be segmented into a space-separated sequence of one or more dictionary words. Note:
  • The same word in the dictionary may be reused multiple times in the segmentation.
  • You may a ssume the dictionary does not contain duplicate words.
Example 1: Input: s = "leetcode", wordDict = ["leet", "code"] Output: true Explanation: Return true because
"leetcode" can be segmented as "leet code" . Example 2: Input: s = "applepenapple", wordDict = ["apple", "pen"] Output: true Explanation: Return true because " applepenapple " can be segmented as " apple pen apple " . Note that you are allowed to reuse a dictionary word. Example 3: Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] Output: false
C++   /* 問題:拆分詞句,看給定的詞句能分被拆分成字典裡面的內容 方法:動態規劃 f[i] 表示s[0,i-1]是否可以被分詞 ,表示在第i個字元後面的隔板 狀態轉移方程:f(i) = any_of(f(j)&&s[j,i-1] ∈ dict); j = 0~i-1 例: Input: s = "leetcode", wordDict = ["leet", "code"] f[0] = true i=1,j=0: l i=2,j=0: le     j=1: e i=3,j=0: lee     j=1: ee     j=2: e i=4,j=0: leet  f[4] = true     j=1: eet     j=2: et     j=3: t ... O(n^2) 假設總共有n個字串,並且字典是用HashSet來維護,那麼總共需要n次迭代,每次迭代需要一個取子串的O(i)操作,然後檢測i個子串,而檢測是constant操作。所以總的時間複雜度是O(n^2)(i的累加仍然是n^2量級),而空間複雜度則是字串的數量,即O(n)(本題還需加上字典的空間) */ class Solution { public :     bool wordBreak ( string s , vector < string > & wordDict )     {         unordered_set < string > new_dict ( wordDict . begin (), wordDict . end ()); //轉化為雜湊表,方便查詢                 //長度為n的字串有n+1個隔板,多分配一個空間以方便後續遞推         vector < bool > f ( s.size() + 1 , false );                 f [ 0 ] = true ; // 空字串,初始化為true,以便後續迭代         for ( int i =  1 ; i < f . size (); i ++) //以s[i-1]字元結尾的子串, i=1~n         {             for ( int j = 0 ; j < i ; j ++) //以s[j]開頭的子串,j=0~i-1             {                 if (f[j] && new_dict . find ( s . substr ( j , i - j )) != new_dict . end ()) //substr[start,len)                 {                     f [i] = true;                     break ;                 }             }         }         return f[s.size()];     } };   Word Break II Given a   non-empty   string   s   and a dictionary   wordDict   containing a list of   non-empty   words, add spaces in   s   to construct a sentence where each word is a valid dictionary word. Return all such possible sentences. Note:
  • The same word in the dictionary may be reused multiple times in the segmentation.
  • You may assume the dictionary does not contain duplicate words.
Example 1: Input: s = " catsanddog " wordDict = ["cat", "cats", "and", "sand", "dog"] Output: [ "cats and dog", "cat sand dog" ] Example 2: Input: s = "pineapplepenapple" wordDict = ["apple", "pen", "applepen", "pine", "pineapple"] Output: [ "pine apple pen apple", "pineapple pen apple", "pine applepen apple" ] Explanation: Note that you are allowed to reuse a dictionary word. Example 3: Input: s = "catsandog" wordDict = ["cats", "dog", "sand", "and", "cat"] Output: []
C++   /* 問題:拆分詞句2,返回所有分隔結果 方法:dfs 聯絡排列組合問題 這裡用一個hash表避免對相同子串s進行重複分隔,減少重複計算 */ class Solution { public :     vector < string > wordBreak ( string s , vector < string >& wordDict )     {         unordered_map < string , vector < string >> m ;         return dfs ( s , wordDict , m );     }     vector < string > dfs ( string s , vector < string >& wordDict , unordered_map < string , vector < string >>& m )     {         if ( m . find ( s ) != m . end ()) return m [ s ]; //如果對s的分隔已經遞迴過了,就直接退出         if ( s . empty ()) return { "" }; //map型資料型別用{},遞迴的出口                 vector < string > res ; //某一次的分隔結果         for ( string word : wordDict ) //遍歷字典中的單詞(遞迴的分支)         {             if ( word == s . substr ( 0 , word . size ()) ) //如果當前單詞在s開頭             {                 //substr 返回子串 [pos, pos+count) 。若請求的子串越過 string 的結尾,或若 count == npos ,則返回的子串為 [pos, size())                 vector < string > rem = dfs ( s . substr ( word . size ()), wordDict , m ); //對該單詞後面的子串遞迴(分支的深度),返回後面子串的分隔結果                                 for ( string str : rem ) //拼接後面子串的分隔結果與當前單詞                 {                     res . push_back ( word + ( str . empty () ? "" : " " ) + str ); //將word和str push到結果向量中,中間用空格隔開,此為某一種結果                 }                             }                     }                 return m [ s ] = res ; //返回對s的分隔結果     } };