此问题是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差,不是吗?
答案 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 )中,甚至没有考虑昂贵的操作(复制list
和dict
)你在第二个循环的主体中执行。
您的第二种方法(技术上不是DFS)与案例复杂性中的第一种方法相同。它们都是 O(n 2 )。但是在第二种方法中,与第一种方法(复制list
和dict
等)相比,您可以减少额外的工作量。因此,您的第一种方法可能会运行得更快,但从长远来看并不重要。对于更大的输入大小,这两种方法都不够高效。
请注意,这是一个名为Subset-sum的非常着名的问题,即NP-Complete。可以使用Dynamic Programming中的Pseudo-polynomial time解决此问题。