回溯这个递归函数的最差时间复杂度

时间:2014-07-14 01:41:33

标签: java algorithm

public static void generateWords(List<List<String>> words) {
    generateWordsHelper("", words);
}

public static void generateWordsHelper(String prefix, List<List<String>> words) {
    if (words.isEmpty()) {
        System.out.println(prefix);
        return;
    }
    for (int i = 0; i < words.size(); i++) {
        for (int j = 0; words.size() > 0 && j < words.get(i).size(); j++) {
            generateWordsHelper(prefix + words.get(i).get(j), words.subList(i+1, words.size()));
        }
    }
}

嗨大家好 这个函数最糟糕的时间复杂度是什么,我该如何计算它。因为它的回溯,我觉得它是O(2 ^ n),但我无法证明它,或解释为什么会这样。

1 个答案:

答案 0 :(得分:1)

很难用列表中String的总数来表达这一点,因为涉及两个变量:外部列表的List<String>个元素的数量,以及每个String中都有List<String>个元素。

为简化起见,假设我们假设 m = words.size(),并且每个List<String>都有 k 元素。 (在现实生活中,所有List<String> s的大小不一定相同。)然后列表中String的总数为 n = mk 。让我们计算调用generateWordsHelper的总次数。如果 m = 0,我们调用它一次,但函数从不以递归方式调用自身。如果 m = 1,则调用该函数一次,然后我们递归地调用它 k 次(因为int j循环),但每次调用时它将在大小为0的子列表上调用。如果 m = 2,则调用该函数一次,然后该函数使用子列表递归调用 k 次大小为1, k 次,大小为0的子列表[但不按此顺序];如果 m = 3,它会使用大小为2的子列表递归地调用 k 次,再次使用大小为1的子列表,再次使用大小为0的子列表。所以我们可以看到模式。如果我们将 f m )表示为初始大小为 m 时调用generateWordHelper的总次数,则

f (0)= 1
    f m )= 1 + k * f m -1) + k * f m -2)+ ... + k * f (0)

适用于

f (0)= 1
    f (1)= 1 + k
    f (2)= 1 + 2 k + k 2
    f (3)= 1 + 3 k + 3 k 2 + k 3

f m )=( k +1) m < / p>

所以我认为这是你正在寻找的公式: O (( k +1) m )。我不认为这可以简单地表达在一个变量 n 中,其中 n 是字符串的总数。如果每个List<String>包含一个元素,那么 k = 1且 n = m ,那么递归调用的数量确实如此 O (2 n ) - 实际上,正好是2 n 。如果我们说每个List<String>平均大小是 z ,那么我们可能会通过使用 k 的公式来接近= z m = n / z ,因此复杂性为 O ((ž 1) 名词 / ž )。

但请注意,我只根据调用递归方法的次数来计算“复杂度”。这并不能说明String操作prefix + words.get(i).get(j)可能与其中一个变量成比例。

相关问题