Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x 此功率集功能的时间和空间复杂性是什么?_Python 3.x_Recursion_Time Complexity_Space Complexity_Powerset - Fatal编程技术网

Python 3.x 此功率集功能的时间和空间复杂性是什么?

Python 3.x 此功率集功能的时间和空间复杂性是什么?,python-3.x,recursion,time-complexity,space-complexity,powerset,Python 3.x,Recursion,Time Complexity,Space Complexity,Powerset,你好,我一直在练习算法和数据结构,我解决了哪个是powerset函数,但我的解决方案似乎太慢了。 代码如下: def subsets(array): set = [array] n = len(array) for i in range(n): tmp_subsets = subsets(array[:i] + array[i+1:]) for subset in tmp_subsets: if subset not

你好,我一直在练习算法和数据结构,我解决了哪个是powerset函数,但我的解决方案似乎太慢了。 代码如下:

def subsets(array):
    set = [array]
    n = len(array)
    for i in range(n):
        tmp_subsets = subsets(array[:i] + array[i+1:])
        for subset in tmp_subsets:
            if subset not in set:
                set.append(subset)
    return set
我知道还有其他更好/更快的解决方案,但我正在努力了解这一解决方案的时间和空间复杂性

我认为这里的时间复杂度是
O(n^n)
,因为递归树每个级别有
n
个分支和
n
个总级别,对吗

因此,它比最优的
O(2^n)
解更差

虽然我不确定空间的复杂性,但我的直觉是
O(2^n)
,但当我画递归树时,它有点混乱,因为我在递归堆栈最大的位置使用的空间是:

space_for_level(0)+space_for_level(1)+...+space_for_level(n)
n + (n-1) +...+ 1 = O(n^2)
但是最后当我返回所有内容时,
set
的大小是
O(2^n)
所以我的空间复杂度是
O(2^n+n^2)=O(2^n)


我的分析在时间和空间上都正确吗?欢迎任何帮助我以更清晰的方式思考的建议。

时间复杂性

时间复杂度可归纳为以下递推关系:

T(n)=n*T(n-1)+n*2^(n-1)

因为有一个主循环运行了
n次
,每次剩余元素的子集(
n-1
)都首先生成(
T(n-1)
,然后循环(
2^(n-1)

注意该关系假设循环中的每一个其他操作都需要恒定的时间,这是一个合理的近似值,因为它在
n
增长时的影响最小。例如,此操作:

if subset not in set
需要固定时间(它需要列表长度中的线性时间,也就是
集合。append(subset)
通常不是固定时间),但是现在让我们忽略它(您可以了解图片以及如何分析代码)

递归关系表明复杂性至少是指数级的

空间复杂性

首先,生成
n
的所有子集,这意味着至少复杂性为
O(2^n)
。然而,由于在每个步骤中递归和重新生成子集,空间复杂度比这还要高。具体而言,在每个循环步骤中,生成
n-1
子集的一个运行副本,然后将其扩充到原始子集。我们有:

S(n)=S(n-1)+2^n

由于对子集的每次调用都会生成
1
剩余子集的中间运行副本(即
S(n-1)
)再加上它将这些子集组合成
2^n
的原始子集


<强>注我们不计算存储子集集的每个项所需的存储量,这本身需要在O(n)< /C>中存储复杂度,但考虑到这是为了简单地存储< <代码> o(1)< /C> >为简单起见(例如,在二进制编码中,将子集存储为一个字,对于较小的

n,它在时间和空间上是指数的。需要应用指数性能的确切形式,但在这种情况下,递归是
T(n)=nT(n-1)
这个定理并不适用……非常感谢你的见解。我认为你对时间复杂性的分析非常准确而且非常有用。但是,当谈到空间复杂性时,我有点困惑。你是说
S(n)=S(n-1)+2^n
其中
2^n
对应于
set
S(n-1)
对应于
tmp_子集
。如果是这样,我们就不能说
s(n-1)=s(n-2)+2^(n-1)…s(1)=s(0)+2
-->
s(n)=O(2^n)
。另一种方法是查看递归树,找出程序何时使用了最多的空间,这在我们开始回溯和
set
开始接近'2^n'之前不会发生,因此我们使用最多内存的时间是我们最后一次对tmp\u子集中的子集执行
操作时:
意思是
set
tmp\u子集
都是
O(2^n)
-->
S(n)=O(2^n)
。让我知道你的想法。
[1,…,n]
的所有子集不是都占用O(n2^(n-1))空间吗?@d\darric,空间复杂性如前所述,因为代码使用了
S(n-1)的临时存储
生成临时
n-1
子集加上返回所有当前子集所需的
2^n
存储。可以尝试说
S(n-1)
只是
2^(n-1)
,但事实并非如此,因为它递归地需要更多空间来生成临时
S(n-2)
子集等等..在任何情况下,人们都可以求解递归关系并获得复杂度的精确形式,我认为(不求解它)是O(n2^n)
order.@NikosM。这可能不是您的意图,但请不要像我们通常那样建议人们进行交叉张贴。建议另一个站点进行重新制定或后续问题当然可以,只要这不会导致不必要的交叉站点重复。谢谢!