该算法查找所有组合的时间复杂度是多少?
Posted
技术标签:
【中文标题】该算法查找所有组合的时间复杂度是多少?【英文标题】:What's time complexity of this algorithm for finding all combinations? 【发布时间】:2014-08-29 20:53:00 【问题描述】:组合 给定两个整数 n 和 k,返回 1 ... n 中 k 个数字的所有可能组合。例如,如果 n = 4 和 k = 2,则解为:
[ [2, 4], [3, 4], [2, 3], [1, 2], [1, 3], [1, 4], ]
个人认为,时间复杂度= O(n^k),输入n和k。
感谢大家的帮助。最后,时间复杂度 = O(C(n,k) * k) = O((n!/(k! * (n - k)!)) * k), n 和 k 是输入, 因为,每次我们得到一个组合时,我们都需要将 subList 列表复制到 one_rest,也就是 O(k), 有 C(n, k) * k。
C++
#include <vector>
using namespace std;
class Solution
public:
vector<vector<int> > combine(int n, int k)
vector<vector<int>> list;
// Input validation.
if (n < k) return list;
int start = 1;
vector<int> subList;
helper(n, k, start, list, subList);
return list;
void helper(int n, int k, int start,
vector<vector<int>> &list, vector<int> &subList)
// Base case.
if (subList.size() == k)
vector<int> one_rest(subList);
list.push_back(one_rest);
return;
if (start > n) return;
for (int i = start; i <= n; i ++)
// Have a try.
subList.push_back(i);
// Do recursion.
helper(n, k, i + 1, list, subList);
// Roll back.
subList.pop_back();
;
【问题讨论】:
【参考方案1】:复杂度为O(C(n,k))
,即O(n choose k)
。
这最终等同于O(min(n^k, n^(n-k)))
。
【讨论】:
怎么可能是 O(min(n^k, n^(n-k)))? 让n=11
和k=8
,n-k = 3
然后11 choose 8 = 165
和11 choose 3 = 165
。你会发现n choose k
对应的k <= n / 2
是O(N^k)
。而对于k > n / 2
,公式为O(n^(n-k))
。你可以把它写成分段函数,基本上就是我刚才在那里描述的,或者你可以简单地说O(min(n^k, n^(n-k))
。如果您查看有关如何针对 k
的特定值计算 n choose k
的公式,这一点会变得更加清晰。
虽然 C(n,k) 确实是 O(n^k) 的一个元素,但如果 k 很大,这是一个非常宽松的上限;例如,C(n, n/2) < 2^n
@Stef 那是我有min
在那里。您使用较小的 O(n^k)
和 O(n^(n-k))
。如果k >> n/2
然后O(n^(n-k))
非常小,应该使用它。可能有一种不需要min()
的方式来重写它,但即使现在也想不到。
@Nuclearman 我应该说“如果 k 接近 n/2”而不是“如果 k 很大”。我很清楚 C(n, k) = C(n, n-k)。这不是我要批评的。我要说的是 n^k 是一个非常松散的界限,除非 k 非常接近 0 或 n。极端情况是 k = n/2:在这种情况下,C(n, k) 小于 2^n,但 n^k = sqrt(n)^n 远大于 2^n。【参考方案2】:
由于您使用的是列表,push_back
和 pop_back
是 O(1)
操作。此外,您最终只生成了一次有效组合。因此,复杂度为O(n choose k)
。
【讨论】:
你能用O(n choose k)这样的组合来写复杂性,还是你必须提供最终的等价。您能否指出我对此的参考。f(x) = O(g(x))
是对f(x)
和g(x)
的限制行为的严格陈述。见here。说O(n choose k)
没有错。但是,根据您的情况,您可能需要不同的 g(x)
。例如,如果您尝试将 O(n choose k)
算法与其他一些指数复杂度算法进行比较,您可能希望将 n choose k
替换为使用 Stirling's approximation 的算法。【参考方案3】:
时间复杂度等于组合的数量。
在本例中为n choose k
。
【讨论】:
+1,简单而明显的答案,因为算法必须生成 all 组合,而这些(对于给定的 n,k)已知为 $n 选择 k $ 这也是算法的时间复杂度(否则算法会产生有偏差的组合,要么是缺失要么是重复)【参考方案4】:我认为不是 O(n^k)。因为想想。让我们假设 n=100 和 k=2。根据您的复杂性,它将是 100 的 2 次方。但是如果它是 n=100 且 k=10,它将是 100 的 10 次方。但是如果您考虑一下,n=100 的组合要多得多,k=2 比 n=100,k=10。复杂性实际上是实际公式:即 n!/(k!(n-k)!)。因此复杂度将是 O(n!/k!(n-k)!)。
【讨论】:
这没有必要矛盾。 Big-O 表示法指定了上限,因此特定的数字示例不太适用于它。n!/k!(n-k)!
是实际的精确计算,因此可以作为复杂性的最严格边界。但是,答案取决于问题的定义。如果k
和n
都是变量,那么复杂度就是O(n!/k!(n-k)!)
。但是如果 k
是常量 - n!/k!(n-k)!=O(n!/k!(n-k)!)=O(n^k)
您能否详细说明一下您是如何通过 K 是恒定的事实获得 O(n^k) 的?我无法跟随你。
@vinicius.olifer 在这里回复旧评论,但可能对未来的人有用。 O(n!/k!(n-k)!)
是最准确的定义,但在大多数情况下讨论大 O 符号时并不是非常有用。阶乘只是增加了通常不需要的复杂性。出于更实际的目的,我上面的答案使用O(min(n^k, n^(n-k)))
。由于 O 仅表示“不比”更差,因此可以使用这两者中的较高者并仅使用 O(n^k),但如果 k >= n/2
更准确地说是 O(n^(n-k))
。以上是关于该算法查找所有组合的时间复杂度是多少?的主要内容,如果未能解决你的问题,请参考以下文章