題目描述
給定一個非空字符串 s 和一個包含非空單詞列表的字典 wordDict,判定 s 是否可以被空格拆分爲一個或多個在字典中出現的單詞。
說明:
- 拆分時可以重複使用字典中的單詞。
- 你可以假設字典中沒有重複的單詞。
示例 1:
輸入: s = "leetcode", wordDict = ["leet", "code"]
輸出: true
解釋: 返回 true 因爲 "leetcode" 可以被拆分成 "leet code"。
示例 2:
輸入: s = "applepenapple", wordDict = ["apple", "pen"]
輸出: true
解釋: 返回 true 因爲 "applepenapple" 可以被拆分成 "apple pen apple"。
注意你可以重複使用字典中的單詞。
示例 3:
輸入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
輸出: false
遞歸解法
以 wordBreak(s, wordDict) 作爲判斷字符串 s 可否拆分爲 wordDict 的函數。則對於字符串 s 和下標 i,若 s[:i+1] 在 wordDict 中,如果 wordBreak(s[i+1:], wordDict) 返回 True,則表示字符串 s 可被拆分爲 wordDict。
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
if not s:
return True
for i in range(len(s)):
if s[:i+1] in wordDict and self.wordBreak(s[i+1:],wordDict):
return True
return False
遞歸運算可能存在大量的重複計算,當字符串較大時可能會超時。
遞歸+存儲中間值解法
以 wordMatch 存儲字符串對應函數值。
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
wordMatch,wordSet=dict(),set(wordDict)
def breakCyc(s):
if not s:
return True
for i in range(len(s)):
if s[:i+1] in wordSet:
flag=wordMatch.get(s[i+1:],-1)
if flag==-1:
flag=breakCyc(s[i+1:])
wordMatch[s[i+1:]]=flag
if flag:
return True
return False
return breakCyc(s)
動態規劃解法
以列表 arr 記錄字符串 s 的每個可拆分前綴的下標,則從上一個前綴繼續拓展遍歷時,若當前的子字符串可拆分,則必然由前面的某一個可拆分前綴和 wordDict 中某個單詞組成。
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
arr,wordSet=[0],set(wordDict)
for i in range(len(s)):
for j in arr[::-1]:
if s[j:i+1] in wordSet:
arr.append(i+1)
break
return arr[-1]==len(s)