高时间复杂度问题的优化(4Sum)
Posted
技术标签:
【中文标题】高时间复杂度问题的优化(4Sum)【英文标题】:Optimization for a high time complexity problem (4Sum) 【发布时间】:2020-08-22 02:16:29 【问题描述】:这是来自 Leetcode 的问题。我根据 3Sum 问题的思想推导出了这个解决方案。
问题是:
给定一个由 n 个整数组成的数组 nums 和一个整数目标,在 nums 中是否存在元素 a、b、c 和 d 使得 a + b + c + d = target?找出数组中所有唯一的四元组,给出目标的总和。
例如
Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.
A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
我的解决方案。
class Solution(object):
def fourSum(self, nums, target):
answer = []
nums.sort()
for i in range(len(nums)-3):
# print('node 1')
for j in range(i+1,len(nums)-2):
# print('node 2')
k,w = j+1,len(nums)-1
while k < w:
sum = nums[i]+nums[j]+nums[k]+nums[w]
if sum == target and [nums[i],nums[j],nums[k],nums[w]] not in answer:
answer.append([nums[i],nums[j],nums[k],nums[w]])
if sum > target:
w-=1
else:
k+=1
return answer
但是算法的速度并不理想。
可以做一些小的改变来加速算法吗?
这段代码有冗余吗? 谢谢
【问题讨论】:
你需要的最小时间复杂度是多少? 还有一件事,我想让你发布一些测试用例。谢谢! @Ava 我目前正在做一个 O(n3) 算法。这是我能想到的最好的了。你是对的,我放了一个测试样本 @Leo 不,你目前是 O(n^6)。请参阅我的更新答案。 【参考方案1】:由于我要使用python,所以我宁愿尝试以pythonic的方式来做。
from itertools import combinations
def fourSum(nums, target):
return list(
num for num in combinations(nums, 4)
if sum(num) == target
)
print(fourSum([1, 0, -1, 0, -2, 2], 0))
为了比较我和你的代码的执行时间,我什至写了下面的脚本。
from itertools import combinations
import timeit, random
def myFourSum(nums, target):
return list(
num for num in combinations(nums, 4)
if sum(num) == target
)
def yourFourSum(nums, target):
answer = []
nums.sort()
for i in range(len(nums)-3):
# print('node 1')
for j in range(i+1,len(nums)-2):
# print('node 2')
k,w = j+1,len(nums)-1
while k < w:
sum = nums[i]+nums[j]+nums[k]+nums[w]
if sum == target and [nums[i],nums[j],nums[k],nums[w]] not in answer:
answer.append([nums[i],nums[j],nums[k],nums[w]])
if sum > target:
w-=1
else:
k+=1
return answer
_list, target = random.sample(range(10000), 10000), random.randint(100, 5000)
setup = "from __main__ import myFourSum"
stmt = f"myFourSum(_list, target)"
print(myFourSum(_list, target))
print(f"Exec. Time: timeit.timeit(setup = setup, stmt = stmt, number = 10000)")
print('-' * 50)
setup = "from __main__ import yourFourSum"
stmt = f"yourFourSum(_list, target)"
print(yourFourSum(_list, target))
print(f"Exec. Time: timeit.timeit(setup = setup, stmt = stmt, number = 10000)")
我把这个留给你,你应该选择哪一个。
【讨论】:
这看起来像是一个糟糕的笑话。你失败了nums = [0, 0, 0, 0, 0]; target = 0
,四次返回同一个四胞胎,而不是 unique 四胞胎。你失败了nums = [100, 100, 100, 100]; target = 400
,返回 no 四胞胎。你的复杂度是 O(n^4)。而这样一个小案例是一个无关紧要和可怕的基准。并且更好地为测试参数使用常量,这样更改它们就不需要更改它们两次(麻烦且容易出错)
@superb rain 是的,我同意。我修复了你提到的所有错误。关于时间复杂度,或许我们可以采用分治法?
您仍然无法通过 target=400 案例,并且您仍在对无关紧要的小案例进行基准测试。
@superbrain 好的,现在它已修复。我忘记把is
换成==
了。无论如何,我还通过 10000 个列表项改进了基准测试。我希望这对现在有所帮助。
现在它给了我NameError: name '_list' is not defined
。【参考方案2】:
可以做一些小的改变来加速算法。
这是一个问题。
但是是的。您的错误只是 not in answer
测试,因为 answer
是一个列表(列表)。改为将其设为一组(元组)。如果需要,最后转换为列表列表。 (如果你这样做on LeetCode,法官可能会接受不正确的类型。)
这会将您当前的 O(n^6) 解决方案变成 O(n^3) 解决方案。例如:
nums = list(range(50))
target = 98
With list: 0.697 seconds
With set: 0.062 seconds
nums = list(range(100))
target = 198
With list: 48.921 seconds
With set: 0.304 seconds
【讨论】:
您介意解释一下为什么将列表设为元组可以降低时间复杂度吗? @Leo 你从哪里得到的?我不是这么说的。以上是关于高时间复杂度问题的优化(4Sum)的主要内容,如果未能解决你的问题,请参考以下文章