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 <= 3001 <= wordDict.length <= 10001 <= wordDict[i].length <= 20s 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.