微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

此 Word Break DFS + Memorization 解决方案的时间复杂度

如何解决此 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) 更糟:

  1. 您忽略了“m”,但 m 是 Omega(log k)。 (因为 k
  2. s.substring 可能是 O(n)。您的代码看起来像 Java,在 Java 中是 O(n)。
  3. 即使 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 举报,一经查实,本站将立刻删除。