关于java:在字典中查找最长单词的代码时间复杂度

Time Complexity of Code for finding longest word inside dictionary

问题如下:你从一个2个字母的单词开始,你可以在单词的前后附加字母。您必须返回字典中存在的最长单词,您可以通过在 2 个字母单词的前后附加字母来形成该单词,并且您形成的每个新单词也必须在字典中

例如:
开始:\\'at\\'

字典:[帽子,聊天,聊天,老鼠,速率,橙色]

输出:\\'chats\\',因为:at -> hat -> chat -> chats

我的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static String longest(ArrayList<String> input) {    
    return helper('at', dict);
}


public static String helper(String in, ArrayList<String> dict) {

    ArrayList<String> maxes = new ArrayList<String>();
    for (char a = 'a'; a < 'z'; a++) {
      String front = Character.toString(a) + in;
      String back = in + Character.toString(a);
      if (dict.contains(front)) {
        maxes.add(helper(front, dict));
      }
      if (dict.contains(back)) {
        maxes.add(helper(back, dict));
      }
    }

    if (maxes.size() == 0) {
      return in;
    }

    String word ="";
    for (String w : maxes) {
      if (w.length() > word.length()) {
        word = w;
      }
    }
    return word;
  }

我想知道这个算法的时间复杂度是多少?我一辈子都想不通。


答案很大程度上取决于您的字典(最大可达长度为 L<=n 1 的 n 个单词)以及用于存储它的数据结构。对 helper 的每次调用(没有它的递归调用)都是 O(n L),其中 dict 是一个 ArrayList,而对于哈希表,它是 O(L)(不存在不太可能的冲突)。 (字典中可能有很长的无法到达的单词,但与它们进行比较仍然只需 O(L),因为您的试用单词不能更长。)

至于对 helper 的调用次数:这只是对通过前置/附加字母相关的单词树进行的深度优先搜索。因此,它是 O(v),其中 v 是访问的顶点数。各种输入词的 v 值也取决于您的字典:当然,v<=n,而且通常要小得多。举个例子:使用我的 /usr/share/dict/words 中的 71813 行都是 ASCII 字母(并且忽略大小写),所考虑的最多的单词是 593(对于 argon 中的 "Ar")。

最坏情况的字典将所有单词组成一个链 "ab"、"abc"、"abcd" 等。您访问每个单词的总成本为 O(vn L )=O(n^3) (O(v L)=O(n^2) 与哈希表)。现实的字典会快得多,不仅因为 L 更小,而且因为 v 更小;不幸的是,确切的加速很难分析。假设 L 是 ??(log(n)); 可能是合理的。 v 作为 n 的函数,没有有意义的渐近表达式,因为现实的字典没有任意大的 n。