题目描述
给定一非空字符串s和一包含非空单词的wordDict。在s中添加空格构成句子,使得每个单词都在wordDict中。输出所有可能的句子。
wordDict中相同的单词可以使用多次;
假设wordDict不包含重复单词。
例子
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:
[]
思想
定义一个函数check - DP判断子字符串是否可以由wordDict中的词汇组成;
(法1 - DFS)
(法2 - DP)
存储截止s[:i], 满足题意的所有可能组合
解法1
DFS - 利用判断当前子串是否可以由wordDict中的词汇组成
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: List[str]
"""
wordDict = set(wordDict)
res = []
self.dfs(s, wordDict, 0, '', res)
return res
def check(self, s, wordDict):
n = len(s)
dp = [False] * (n + 1) # s[:i]
dp[0] = True
for i in range(1, n+1):
for j in range(i-1, -1, -1):
if dp[j] and s[j:i] in wordDict:
dp[i] = True
break
return dp[-1]
def dfs(self, s, wordDict, i, temp, res):
if i == len(s):
res.append(temp[:-1])
if self.check(s[i:], wordDict):
for j in range(i+1, len(s)+1):
if s[i:j] in wordDict:
self.dfs(s, wordDict, j, temp + s[i:j] + ' ', res)
(改进-法1)
dp已经统计了截止当前位置的字符串是否可以由wordDict中的词汇组成。
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: List[str]
"""
wordDict = set(wordDict)
dp = self.check(s, wordDict)
res = []
self.dfs(s, wordDict, dp, '', res)
return res
def check(self, s, wordDict):
n = len(s)
dp = [False] * (n+1)
dp[0] = True
for i in range(1, n+1):
for j in range(i-1, -1, -1):
if dp[j] and s[j:i] in wordDict:
dp[i] = True
break
return dp
def dfs(self, s, wordDict, dp, temp, res):
if not s:
res.append(temp[:-1])
for i in range(len(s)):
if dp[i] and s[i:] in wordDict:
self.dfs(s[:i], wordDict, dp, s[i:] + ' ' + temp, res)
解法2
DP。dp[i]表示截止s[:i], 满足题意的所有可能组合
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: List[str]
"""
wordDict = set(wordDict)
n = len(s)
dp = [[] for _ in range(n+1)] # 截止s[:i], 满足题意的所有可能组合
dp[0] = ['']
if self.check(s, wordDict):
for i in range(1, n+1):
temp = []
for j in range(i):
if dp[j] and s[j:i] in wordDict:
for prev in dp[j]:
space = ' ' if prev else ''
temp.append(prev + space + s[j:i])
dp[i] = temp
return dp[-1]
def check(self, s, wordDict):
n = len(s)
dp = [False] * (n+1)
dp[0] = True
for i in range(1, n+1):
for j in range(i-1, -1, -1):
if dp[j] and s[j:i] in wordDict:
dp[i] = True
break
return dp[-1]
题目描述
给定一输入字符串s和一模式p,对两者进行正则表达式匹配(只考虑 ‘.’ 和 ‘*’)。
s可以为空或只包含a-z小写字母;p可以为空或只包含a-z小写字母或’.’ / ‘*’。
’.’ 匹配任意单字符;’*’ 匹配0次或多次前缀元素。
例子
Example 1:
Input:
s = “aa”
p = “a”
Output: false
Explanation: “a” does not match the entire string “aa”.
Example 2:
Input:
s = “aa”
p = “a*”
Output: true
Explanation: ‘*’ means zero or more of the precedeng element, ‘a’. Therefore, by repeating ‘a’ once, it becomes “aa”.
Example 3:
Input:
s = “ab”
p = “.*”
Output: true
Explanation: “.*” means “zero or more (*) of any character (.)”.
Example 4:
Input:
s = “aab”
p = “c*a*b”
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches “aab”.
Example 5:
Input:
s = “mississippi”
p = “mis*is*p*.”
Output: false
思想
(法1 - 递归)
首先判断第2位是不是*。(Yes)重复0次/第一位已匹配,重复多次[重复1次];(No)判断第一位匹配,s[1:]和p[1:]递归
(法2 - DP)
dp[i][j] 表示 s[:i] 和 p[:j] 是否匹配成功
初始化:dp[0][0] - 两个空字符串匹配成功;dp[0][j] - 空字符串只和*匹配成功。
状态方程:
1)p[j-1] == ‘.’ or s[i-1],则dp[i][j] = dp[i-1][j-1] ---- p当前字符和s当前字符匹配;
2)p[j-1] == ‘*’ ---- p当前字符为 ‘*’
2.1) p[j-2] == s[i-1] or ‘*’,则dp[i][j] = dp[i][j-2] or dp[i-1][j-2] or dp[i-1][j] ---- p*前面字符和s当前字符匹配,*匹配0次/1次/多次
2.2) p[j-2] != s[i-1],则dp[i][j] = dp[i][j-2] ---- p*前面字符和s当前字符不匹配,*匹配0次;
解法1
递归,首先判断第2位是不是*。
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
if not s and not p:
return True
if not p and s:
return False
# 首先判断第2位是不是*
if len(p) > 1 and p[1] == '*':
if self.isMatch(s, p[2:]): # 重复0次
return True
if s and (p[0] == '.' or p[0] == s[0]): # 第一位已经匹配, 重复多次/1次
return self.isMatch(s[1:], p)
if s and (p[0] == '.' or p[0] == s[0]):
return self.isMatch(s[1:], p[1:])
return False
解法2
DP。根据当前为字符是否匹配;当前位字符是否为/* → 前一位字符是否匹配
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
m, n = len(s), len(p)
dp = [[False] * (n+1) for _ in range(m+1)] # dp[i][j] - s[:i] and p[:j]
dp[0][0] = True
for j in range(1, n+1):
if p[j-1] == '*' and dp[0][j-2]:
dp[0][j] = True
for i in range(1, m+1):
for j in range(1, n+1):
if p[j-1] == s[i-1] or p[j-1] == '.':
dp[i][j] = dp[i-1][j-1]
elif p[j-1] == '*' and j > 1:
if p[j-2] == s[i-1] or p[j-2] == '.':
dp[i][j] = dp[i][j-2] or dp[i-1][j-2] or dp[i-1][j] # 0 times/1 times/multiple times
else:
dp[i][j] = dp[i][j-2] # zero times
return dp[-1][-1]