class Solution { private fun precomputeFrom( words: List<String>, s: String, dp: Map<Int, List<String>>, start: Int, ): List<String> { val valid = mutableListOf<String>() (start..<s.length) .map { end -> end to s.substring(start..end) } .filter { (_, word) -> words.contains(word) } .forEach { (end, word) -> when { end == s.length - 1 -> valid.add(word) else -> { dp[end + 1]?.forEach { suffix -> valid.add("$word $suffix") } } } } return valid } fun wordBreak( s: String, wordDict: List<String>, ): List<String> { val dp = mutableMapOf<Int, List<String>>() s.indices.reversed().forEach { start -> dp[start] = precomputeFrom(wordDict, s, dp, start) } return dp.getOrDefault(0, emptyList()) } } fun main() { val s = Solution() check( s.wordBreak("catsanddog", listOf("cat", "cats", "and", "sand", "dog")).sorted() == listOf( "cats and dog", "cat sand dog", ).sorted(), ) check( s.wordBreak("pineapplepenapple", listOf("apple", "pen", "applepen", "pine", "pineapple")).sorted() == listOf( "pine apple pen apple", "pineapple pen apple", "pine applepen apple", ).sorted(), ) check( s.wordBreak("catsandog", listOf("cats", "dog", "sand", "and", "cat")) == emptyList<String>(), ) }