子集总和:为什么DFS +修剪比循环更快2?

时间:2016-10-09 19:02:16

标签: python algorithm loops recursion time-complexity

此问题是leetcode 416 Partition Equal Subset Sum。

#2 for loop, which got TLE
class Solution(object):
    def canPartition(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        nums.sort()
        allsum = sum(nums)
        if allsum % 2 == 1:
            return False
        subsets = {() : 0}
        temp = dict(subsets)
        for each in nums:
            for subset in subsets:
                new = temp[subset] + each
                if new * 2 == allsum:
                    return True
                elif new * 2 < allsum:
                    temp[tuple(list(subset) + [each])] = new
                else:
                    del temp[subset]
            subsets = dict(temp)
        return False

DFS + pruning:
class Solution(object):
    def canPartition(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        nums.sort()
        if sum(nums) % 2 != 0:
            return False
        else:
            target = sum(nums) / 2
        return self.path(nums, len(nums), target)

def path(self, nums, length, target):#DFS + pruning
    if target == 0:
        return True
    elif target < 0 or (target > 0 and length == 0):
        return False
    if self.path(nums, length - 1, target - nums[length - 1]):
        return True
    return self.path(nums, length - 1, target)

为什么2 for循环比DFS慢?他们都修剪了,我认为DFS的时间复杂度,这是一个np问题,对于循环应该比2差,不是吗?

1 个答案:

答案 0 :(得分:0)

仅仅因为你使用了两个循环,并不意味着你的算法在 O(n 2 或多项式中。算法的复杂性取决于每个循环执行的次数。 在这部分代码中:

    for each in nums:
        for subset in subsets:
            ....

第一个循环将运行 n 次,因为nums的大小为 n 并且它不会更改。但是,每次迭代后,subsets的大小会增加2倍。因此,第二个for循环的主体将执行1 + 2 + 4 + 8 + 16 + 32 + ... + 2^n = 2^(n+1)次。

所以你的算法在 O(2 n 中,甚至没有考虑昂贵的操作(复制listdict)你在第二个循环的主体中执行。

您的第二种方法(技术上不是DFS)与案例复杂性中的第一种方法相同。它们都是 O(n 2 。但是在第二种方法中,与第一种方法(复制listdict等)相比,您可以减少额外的工作量。因此,您的第一种方法可能会运行得更快,但从长远来看并不重要。对于更大的输入大小,这两种方法都不够高效。

请注意,这是一个名为Subset-sum的非常着名的问题,即NP-Complete。可以使用Dynamic Programming中的Pseudo-polynomial time解决此问题。