人生路上总有很多遗憾
每个人都会这么安慰着自己
但当我碰到这样的遗憾时
我肯定要豁出一切去尝试弥补这样的遗憾
哪怕受人嘲讽!!!
139-单词拆分
给定一个非空字符串 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
思路:
本题我也采用了两种方法,即回溯法和动态规划法,但效果天差地别。
方法一 回溯法:
关于回溯法我之前写了一篇文章专门介绍,各位读者可以看看,里面我详细介绍了回溯法的求解步骤,相信会对大家有所出发。
https://blog.csdn.net/weixin_36431280/article/details/84891567
于本题而言,无非就是从给定字符串s的第一个字符开始遍历,如果截取的子串刚好出现在wordDict中,那么接着该子串的位置继续往后遍历,重复同样操作,如果最后字符串s分割成的几个子串刚好都出现在wordDict中,那么输出True,反之输出False。这也就是回溯的思想,其实很easy!
代码如下:
class Solution(object):
# 回溯法
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
def back(start=0, flag=False):
if start >= len(s):
return True
for end in range(start, len(s)):
sub_str = s[start:end+1]
if sub_str in wordDict:
flag = back(end+1)
if flag is True:
return True
return False
return back()
if __name__ == "__main__":
s = "aaaaaaa"
wordDict = ["aaaa","aaa"]
flag = Solution().wordBreak(s, wordDict)
print(flag)
但是超出时间限制了啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊!!!气死我了,没办法,效率不行,只能是试试动态回归算法了。
方法二:动态规划法
说到动态回归,我之前也写了一篇文章来专门介绍动态回归算法的求解步骤,大家也可以看看找找灵感。
https://blog.csdn.net/weixin_36431280/article/details/86616672
大致思路就是:
定义一个标记列表flag,flag[i]表示到第i-1个字符时,是否为能被拆分为字典里的单词
状态转移矩阵:
flag[j] = flag[i] and s[i:j+1] in wordDict
代码如下:
class Solution(object):
# 本题回溯法超出时间限制,采用动态回归法
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
# 初始化标记列表
flag = [True]+[False]*len(s)
for start in range(len(s)):
if flag[start]:
for end in range(start+1, len(s)+1):
if s[start:end] in wordDict:
flag[end] = True
return flag[-1]
if __name__ == "__main__":
s = "aaaaaaa"
wordDict = ["aaaa","aaa"]
flag = Solution().wordBreak(s, wordDict)
print(flag)
执行效率中等吧,在70%左右。