对于有两个单词的情况,只要考虑将单词分成两个的所有可能方法,然后检查每一半看它是否是一个有效的单词,就可以解决这个问题。如果输入字符串的长度为 n,那么拆分字符串的方法只有 O(n) 种。如果您将字符串存储在支持快速查找的结构中(例如,trie 或哈希表)。
更有趣的情况是当你有 k > 2 个单词来拆分单词时。为此,我们可以使用一个非常优雅的递归公式:
如果一个单词可以拆分为一个单词,然后一个单词可以拆分为 k - 1 个单词,则该单词可以拆分为 k 个单词。
递归的基本情况是,只有当它是空字符串时,一个单词才能被分成零个单词,这很简单。
为了使用这种递归洞察,我们将修改原始算法,将单词的所有可能拆分考虑为两部分。一旦我们进行了拆分,我们可以检查拆分的第一部分是否是一个单词,以及拆分的第二部分是否可以分成 k - 1 个单词。作为一种优化,我们不会对所有可能的拆分进行递归,而只是对我们知道第一个单词有效的那些拆分进行递归。下面是一些用 Java 编写的示例代码:
public static boolean isSplittable(String word, int k, Set<String> dictionary) {
/* Base case: If the string is empty, we can only split into k words and vice-
* versa.
*/
if (word.isEmpty() || k == 0)
return word.isEmpty() && k == 0;
/* Generate all possible non-empty splits of the word into two parts, recursing on
* problems where the first word is known to be valid.
*
* This loop is structured so that we always try pulling off at least one letter
* from the input string so that we don't try splitting the word into k pieces
* of which some are empty.
*/
for (int i = 1; i <= word.length(); ++i) {
String first = word.substring(0, i), last = word.substring(i);
if (dictionary.contains(first) &&
isSplittable(last, k - 1, dictionary)
return true;
}
/* If we're here, then no possible split works in this case and we should signal
* that no solution exists.
*/
return false;
}
}
这段代码,在最坏的情况下,运行时间为 O(nk),因为它试图将字符串的所有可能分区生成 k 个不同的片段。当然,这种最坏情况的行为不太可能发生,因为大多数可能的拆分最终不会形成任何单词。