【LeetCode & 劍指offer刷題】動態規劃與貪婪法題15:Word Break(系列)
阿新 • • 發佈:2019-01-06
【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...)
Word Break(系列)
Word Break Given a non-empty string s and a dictionary wordDict containing a list of non-empty-
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.
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.
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的分隔結果 } };