本題難度:Hard
作題日期:2017年3月26日
本題地址: leetcode.com/problems/wo…javascript
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. You may assume the dictionary does not contain duplicate words.
Return all such possible sentences.
For example, given
s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].
A solution is ["cats and dog", "cat sand dog"].複製代碼
這道題是本週關於回溯的 Hard 題。java
首先能想到的是暴力法,遍歷全部的可能。算法
以題意中的例子作分析數組
s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].緩存
咱們從左到右遍歷 catsanddog:學習
步驟 3 ,一直遞歸下去,咱們能夠獲得結果 ["cat sand dog"]優化
代碼以下:spa
圖三的代碼是暴力搜索全部的可能,會引發 超時異常(黑話是 TLE, 全稱 Time Limit Exceeded),以下圖所示的case。code
通過觀察,咱們發現圖四的test case有一個特色,就是有不少重複的字符: 有不少重複的子串,在暴力算法中有大量的重複計算。cdn
因此,咱們能夠在圖三的代碼的基礎上作優化:緩存結果。
在圖一和圖二的分析中,咱們能夠知道,遍歷全部的可能解的過程當中 ,有許多重複的分支。
以 s = "aaaaaaaaaa", word_dic = ["aa", "aaa", "aaaa", "aaaaa"]
爲例子
如圖五所示,在某一次遞歸求解的過程當中,子串 "aa" 會被被重複的計算 5 次(若是是屢次遞歸,計算的次數會更多)。咱們能夠將 "aa" 的結果緩存到一個 HashTable 中,這樣就能夠減小大量重複的計算。
Tips: 緩存通常都是用哈希,數組用的比較少,由於用數組會有空間浪費。
Tips: 自頂向下的DP其實就是暴力搜索 + 緩存。
在上面的分析中,咱們能夠發現一個規律:在遞歸的過程當中,咱們實際上是將字符串分紅兩個子串:
因此,咱們能夠獲得以下的思路:假設 字符串當前的位置是 n
,f(n)
表示全部的可能解, w(x)
表示 從位置 x
到 n
的子串:
f(n) = w(n) f(n-1) + w(n-1) f(n-2) + ... + w(0)
以 catsanddog 爲例子,以下圖所示
代碼實現以下
Tips 1: 自底向上的DP有一個小竅門:逆向思考。好比咱們在分析該問題的時候,通常是考慮從起始點 0 到 結束點 i 的子串結果,這不利於推導DP公式。咱們應該這樣思考:以 i 爲結尾的子串做爲處理的單元。這麼思考的好處,咱們會自動的思考 i - 1 與 i 之間的關係,而且方便的推導他們之間的關係。
每日一道算法題是一個純粹的算法學習社區:經過天天一塊兒作一道算法題來提高咱們的算法能力。
每日一題算法羣如今一共有3000位小夥伴:有來自北美和國內頂尖名校的本科生、研究生和博士生;也有來自國內外各大互聯網公司(Google, Facebook, 亞馬遜, 百度, 阿里, 騰訊等)的經驗豐富的開發者。
你們彙集只爲一個目的:天天一塊兒學習算法!
咱們堅信:學習算法是一種信仰!
長按下面的二維碼,關注每日一道算法題公衆號,跟咱們一塊兒學習算法!