leetcode第139题 单词的拆分
**需求:**给定义一个字符串和一个字符串数组,看看字符串是不是可以由空格拆分成一个或者是多个在字典中出现的单词
**思路:**暴力破解
- 从0开始一个一个的列举,假如匹配到了一个数组中的字符串,我就继续匹配,如果接下来的也能够匹配成功,返回true
- 用了一个备忘录记录我已经匹配的结果
- start代表的是节点的状态
- 用一个数组,存储计算的结果,下次遇到相同的子问题,直接返回命中的缓存值,就不用调重复的递归
DFS+记忆化代码
func canBreak(start int, s string, wordMap map[string]bool, memo map[int]bool) bool {
if start == len(s) {
return true
}
if res, ok := memo[start]; ok {
return res
}
//这里为什么会是start + 1呢? 我有点不太理解
for i := start + 1; i <= len(s); i++ {
prefix := s[start:i]
if wordMap[prefix] && canBreak(i, s, wordMap, memo) {
memo[start] = true
return true
}
}
memo[start] = false
return false
}
func wordBreak(s string, wordDict []string) bool {
wordMap := map[string]bool{}
for _, v := range wordDict {
wordMap[v] = true
}
memo := make(map[int]bool)
return canBreak(0, s, wordMap, memo)
}
BFS
- 这种Bfs和我平时写的不是很一样,他是对多种情况进行处理的,我必须命中至少一个字符串数组中的一个元素,匹配一个过一个,当匹配到最后一个的时候,我们发现i == len 可以return true
func wordBreak(s string, wordDict []string) bool {
l := len(s)
wordMap := map[string]bool{}
for _, v := range wordDict {
wordMap[v] = true
}
queue := []int{}
queue = append(queue, 0)
visited := map[int]bool{}
for len(queue) != 0 {
start := queue[0]
queue = queue[1:]
if visited[start] {
continue
}
visited[start] = true
for i := start + 1; i <= l; i++ {
prefix := s[start:i]
if wordMap[prefix] {
if i < l {
queue = append(queue, i)
} else {
return true
}
}
}
}
return false
}
动态规划
动态规划写的时候还算是比较顺手的,因为已经把回溯的那种情况写出来了
- dp数组的定义 dp[i] 以i结尾的字符串可以拆分成字典中的所有字符串。
- base case:dp[0] === true 意思是 以0结尾的字符串可以被拆分出来字典中的所有字符
- 只有让dp【0】为真,的dp【i + 1】才会只取决于s【0 :i】是否为单个的单词,才能用上这个状态转移方程
优化:
执行的过程中,发现dp【i】 == true 直接跳出内层循环
当dp【j】 == false continue
func wordBreak(s string, wordDict []string) bool {
wordMap := map[string]bool{}
for _, v := range wordDict {
wordMap[v] = true
}
dp := make([]bool, len(s)+1)
dp[0] = true
for i := 1; i <= len(s); i++ {
for j := i - 1; j >= 0; j-- {
if dp[i] == true {
break
}
if dp[j] == false {
continue
}
suffix := s[j:i]
if wordMap[suffix] && dp[j] {
dp[i] = true
break
}
}
}
return dp[len(s)]
}