题目
给定一个非空字符串 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-break
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
端午节一早遇到这道题整个人都是暴力法,因为赶时间,就直接放下,留下未解之谜!下午终于有时间好好琢磨题目,哇咔咔,惊艳到我了,多么美丽的回溯法+memo。
官方题解说是动态规划,但是这种说法很让我困惑,还是看到回溯两个字让我茅塞顿开。
以“leetcode”举例,从左往右开始遍历,检查"l"是否在字典中,不在就回溯回去;检查“le”是否在字典中,不在就继续回溯。这里为了减少重复的计算,将已经遍历在字典中的字符串记录在memo中。这里还巧妙地把memo的第一个值置为true,所以我们回溯的起点是memo为true。
show me the code
func wordBreak(s string, wordDict []string) bool {
wordDictSet := make(map[string]bool)
for _, w := range wordDict {
wordDictSet[w] = true
}
memo := make([]bool, len(s) + 1)
memo[0] = true
for i := 1; i <= len(s); i++ {
for j := 0; j < i; j++ {
if memo[j] && wordDictSet[s[j:i]] {
memo[i] = true
break
}
}
}
return memo[len(s)]
}
总结
熟能生巧,practice makes perfect。