如何解决此 Word Break DFS + Memorization 解决方案的时间复杂度
在处理 wordBreak 问题时,我发现这个解决方案非常简洁。但不确定时间复杂度。有人可以帮忙吗?
我的理解是最坏的情况,O(n*k),n是wordDict的大小,k是String的长度。
class Solution {
public boolean wordBreak(String s,List<String> wordDict) {
return wordBreak(s,wordDict,new HashMap<String,Boolean>());
}
private boolean wordBreak(String s,List<String> wordDict,Map<String,Boolean> memo) {
if (s == null) return false;
if (s.isEmpty()) return true;
if (memo.containsKey(s)) return memo.get(s);
for (String dict : wordDict) { //number of words O(n)
//startsWith is bounded by the length of dict word,avg is O(m),can be ignored
//substring is bounded by the length of dict word,avg is O(k),k is the length of s
//wordBreak will be executed k/m times,k is the length of s,worse case k times... when a single letter is in the dict
if (s.startsWith(dict) && wordBreak(s.substring(dict.length()),memo)) {
memo.put(s,true);
return true;
}
}
memo.put(s,false);
return false;
}
}
解决方法
由于以下几个原因,它比 O(nk) 更糟:
- 您忽略了“m”,但
m
是 Omega(log k)。 (因为 k -
s.substring
可能是 O(n)。您的代码看起来像 Java,在 Java 中是 O(n)。 - 即使
s.substring
是线性的,您的地图也需要对字符串进行哈希处理,因此您的地图操作是 O(n)(请仔细注意 --n
是字符串的大小,而不是哈希表的大小就像通常一样)。
可能这意味着您的复杂度为 O(n^2k*logk)。
您可以轻松修复 3 -- 您可以使用 s.length
而不是 s
作为哈希表的键。
问题 2 很容易解决,但修复起来有点烦人——您可以使用一个变量来索引字符串,而不是对字符串进行切片。您可能必须自己重写 startsWith
才能使用此索引(或使用特里树 - 见下文)。如果您的编程语言具有 O(1) 切片操作(例如,C++ 中的 string_view
),那么您可以改用它。
问题 1 只是理论上的,因为对于真实的单词列表,与字典的长度或输入字符串的潜在长度相比,m 真的很小。
请注意,使用字典树而不是单词列表可能会导致巨大的时间改进,现实示例是线性的,不包括字典构造(尽管恶意选择字典和输入字符串的最坏情况示例将是 O(nk)).
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。