有没有时间复杂度为O(n^2)的算法可以生成一个数组的所有子序列?

8

我想知道是否有一种O(n^2)复杂度的算法可以生成数组的所有子序列。我知道一种算法,但它需要O((2^n)*n)的时间。

int main() {
    int n; 
    cin >> n;
    vector<int> a(n);
    for(int i = 0; i < n; ++i) 
        cin >> a[i];
    int64_t opsize = pow(2,n);
    for (int counter = 1; counter < opsize; counter++) {
        for (int j = 0; j < n; j++) {
           if (counter & (1 << j))
                 cout << a[j] << " ";
        }
        cout << endl;
    }
}

为了提高性能,您可以将 endl 替换为 '\n' - Marek R
2个回答

17

不行

由于存在O(2^n)个子序列,因此没有小于O(2^n)的算法复杂度。您需要打印它们中的每一个,因此时间复杂度必须大于或等于O(2^n)


2
此外,最长的子序列将具有长度n,因此您需要迭代整个数组,它将是(2^n)* n。 - Kepotx
你可以直接从答案中推断出来。我已经明确表达了。 - random40154443
抱歉,我的n2搞反了。好答案。 - NathanOliver

1
您无法改善算法复杂度,但可以改进流的使用方式。 正如其他答案所指出的那样,o(n * 2^n) 是您能得到的最佳结果。
当您使用 std::endl 时,会刷新流的缓冲区。为了获得最佳性能,缓冲区应在填满时自动刷新。 由于每个子序列都必须相当短(最多64个元素),这意味着您经常刷新流并严重影响性能。 因此,将 std::endl 替换为 '\n' 将提供显着的性能改进。
其他可帮助改进流性能的技巧:
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n; 
    cin >> n;

问题不在于复杂度,而在于流的使用方式。实际上,endl\n并不会改变任何东西。即使对于小于一百的n值,该算法也需要数百万年才能完成。 - fjardon
正如@DeepankarArya所指出的那样,您无法改善复杂性,因此您可以通过消除瓶颈来改进代码,从而提高性能。这就是我的答案所做的。尝试使用可以在合理时间内完成的数据,并查看其有多大的改进。 - Marek R
实现限制将 n 限制为 62 个项目(仍然需要很长时间)。 - Marek R
我的观点是,即使你能做的唯一一件事就是改进I/O,真正的问题仍然是复杂性,这与你在回答中所说的相反。你没有回答“是否有任何O(n^2)算法?”这个问题。 - fjardon
我已经指出你不能改进算法复杂度,我已经重新表述第一句话以使其更清晰。 - Marek R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接