Medium
Given a string s
and a dictionary of strings wordDict
, return true
if s
can be segmented into a space-separated sequence of one or more dictionary words.
Note that the same word in the dictionary may be reused multiple times in the segmentation.
Example 1:
Input: s = “leetcode”, wordDict = [“leet”,”code”]
Output: true
Explanation: Return true because “leetcode” can be segmented as “leet code”.
Example 2:
Input: s = “applepenapple”, wordDict = [“apple”,”pen”]
Output: true
Explanation: Return true because “applepenapple” can be segmented as “apple pen apple”. Note that you are allowed to reuse a dictionary word.
Example 3:
Input: s = “catsandog”, wordDict = [“cats”,”dog”,”sand”,”and”,”cat”]
Output: false
Constraints:
1 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s
and wordDict[i]
consist of only lowercase English letters.wordDict
are unique.To solve the “Word Break” problem:
The problem requires us to determine if a string s
can be segmented into a sequence of words from a dictionary wordDict
.
s
such that each partition is a word from wordDict
.wordDict
can be reused multiple times.canBeBroken
) that will attempt to break down the string s
starting from each index.visited
array) helps avoid redundant computations by remembering if a substring starting from a particular index has already been processed.Implementation Details:
wordDict
into an array of characters (words
). Initialize sSlice
as an array of characters from s
.canBeBroken
):
startIndex
equals chars.endIndex
, return true
, indicating that the entire string has been successfully segmented.visited[startIndex]
is true
to skip processing if the substring starting from startIndex
has already been explored.words
:
chars
) starts with the current word
.canBeBroken
with the remaining substring (chars[startIndex.advanced(by: word.count)...]
).true
, return true
immediately.visited[startIndex]
as true
and return false
.s
is empty or where no segmentation is possible with the given wordDict
.s
and the number of words in wordDict
.visited
array.Here’s the Swift implementation of the approach:
class Solution {
func wordBreak(_ s: String, _ wordDict: [String]) -> Bool {
var words = \[\[Character]]()
for word in wordDict {
words.append(Array(word))
}
let sSlice = Array(s)[...]
var visited = Array(repeating: false, count: sSlice.count)
return canBeBroken(sSlice, words, &visited)
}
func canBeBroken(
_ chars: ArraySlice<Character>,
_ words: [[Character]],
_ visited: inout [Bool]
) -> Bool {
let startIndex = chars.startIndex
guard startIndex != chars.endIndex else { return true }
guard !visited[startIndex] else { return false }
for word in words {
guard chars.starts(with: word) else { continue }
if canBeBroken(chars[startIndex.advanced(by: word.count)...], words, &visited) {
return true
}
}
visited[startIndex] = true
return false
}
}
wordBreak
function):
wordDict
into arrays of characters (words
).s
into an array of characters (sSlice
).visited
array to keep track of whether a substring starting from each index has been explored.canBeBroken
):
startIndex
equals chars.endIndex
, return true
, indicating successful segmentation.visited[startIndex]
is true
to avoid redundant computations.words
:
chars
) starts with the current word
.canBeBroken
with the remaining substring (chars[startIndex.advanced(by: word.count)...]
).true
, immediately return true
.visited[startIndex]
as true
and return false
.This approach ensures that we explore all possible ways to segment s
using words from wordDict
while efficiently handling overlapping subproblems using memoization.