[每日一題]140. Word Break II

每日一題發表於2017-03-27

題目描述

本題難度:Hard
做題日期:2017年3月26日
本題地址: leetcode.com/problems/wo…

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 題。

暴力法

首先能想到的是暴力法,遍歷所有的可能。

以題意中的例子做分析

s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].


[每日一題]140. Word Break II

圖一

我們從左到右遍歷 catsanddog:

  1. 當前子串為 c,不符合要求
  2. 當前子串為 ca,不符合要求
  3. 當前子串為 cat,符合要求,接著求 sanddog 子串的結果, 如圖二所示
  4. 當前子串是 cats, 符合要求...

[每日一題]140. Word Break II

圖二

步驟 3 ,一直遞迴下去,我們可以得到結果 ["cat sand dog"]

程式碼如下:


[每日一題]140. Word Break II
圖三

圖三的程式碼是暴力搜尋所有的可能,會引起 超時異常(黑話是 TLE, 全稱 Time Limit Exceeded),如下圖所示的case。


[每日一題]140. Word Break II

圖四

經過觀察,我們發現圖四的test case有一個特點,就是有很多重複的字元: 有很多重複的子串,在暴力演算法中有大量的重複計算。

所以,我們可以在圖三的程式碼的基礎上做優化:快取結果。

DP = 記憶優化 + 剪枝

在圖一和圖二的分析中,我們可以知道,遍歷所有的可能解的過程中 ,有許多重複的分支。

s = "aaaaaaaaaa", word_dic = ["aa", "aaa", "aaaa", "aaaaa"] 為例子


[每日一題]140. Word Break II

圖五

如圖五所示,在某一次遞迴求解的過程中,子串 "aa" 會被被重複的計算 5 次(如果是多次遞迴,計算的次數會更多)。我們可以將 "aa" 的結果快取到一個 HashTable 中,這樣就可以減少大量重複的計算。

Tips: 快取一般都是用雜湊,陣列用的比較少,因為用陣列會有空間浪費。


[每日一題]140. Word Break II

圖六

Tips: 自頂向下的DP其實就是暴力搜尋 + 快取。

自底向上的思路

在上面的分析中,我們可以發現一個規律:在遞迴的過程中,我們其實是將字串分成兩個子串:

  1. 將10個a, 分成2個a 和 8 個a 的結果的組合: "aa" + "aaaaaaaa"
  2. 8 個 a 又可以分成 2 個 a 和 6 個 a的組合: "aa" + "aaaaaa"
  3. ... ...

所以,我們可以得到如下的思路:假設 字串當前的位置是 nf(n) 表示所有的可能解, w(x) 表示 從位置 xn 的子串:

f(n) = w(n) f(n-1) + w(n-1) f(n-2) + ... + w(0)

以 catsanddog 為例子,如下圖所示


[每日一題]140. Word Break II

圖七

程式碼實現如下

[每日一題]140. Word Break II

Tips 1: 自底向上的DP有一個小竅門:逆向思考。比如我們在分析該問題的時候,一般是考慮從起始點 0 到 結束點 i 的子串結果,這不利於推導DP公式。我們應該這樣思考:以 i 為結尾的子串作為處理的單元。這麼思考的好處,我們會自動的思考 i - 1 與 i 之間的關係,並且方便的推導他們之間的關係。

最佳提交

[每日一題]140. Word Break II

關於我們

每日一道演算法題是一個純粹的演算法學習社群:通過每天一起做一道演算法題來提升我們的演算法能力。

每日一題演算法群現在一共有3000位小夥伴:有來自北美和國內頂尖名校的本科生、研究生和博士生;也有來自國內外各大網際網路公司(Google, Facebook, 亞馬遜, 百度, 阿里, 騰訊等)的經驗豐富的開發者。

大家聚集只為一個目的:每天一起學習演算法!

我們堅信:學習演算法是一種信仰!

長按下面的二維碼,關注每日一道演算法題公眾號,跟我們一起學習演算法!

[每日一題]140. Word Break II

附錄


[每日一題]140. Word Break II

[每日一題]140. Word Break II

[每日一題]140. Word Break II

[每日一題]140. Word Break II

[每日一題]140. Word Break II

相關文章