Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.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中的四和算法_Python_Algorithm_Combinatorics - Fatal编程技术网

Python中的四和算法

Python中的四和算法,python,algorithm,combinatorics,Python,Algorithm,Combinatorics,我试图找出一个列表中是否有4个和为0的元素(稍后再找出这些元素是什么)。我正在尝试根据中描述的偶数k算法制定解决方案 我使用标准库中的组合在Python中获得这段代码 def foursum(arr): seen = {sum(subset) for subset in combinations(arr,2)} return any(-x in seen for x in seen) 但是对于像[-1,1,2,3]这样的输入,这是失败的。它失败是因为它将总和(-1+1)与自身匹配。我认

我试图找出一个列表中是否有4个和为0的元素(稍后再找出这些元素是什么)。我正在尝试根据中描述的
偶数k
算法制定解决方案

我使用标准库中的
组合
在Python中获得这段代码

def foursum(arr):
  seen = {sum(subset) for subset in combinations(arr,2)}
  return any(-x in seen for x in seen)
但是对于像[-1,1,2,3]这样的输入,这是失败的。它失败是因为它将总和(-1+1)与自身匹配。我认为当我想找到元素时,这个问题会变得更糟,因为你可以用6种方式将一组4个不同的项分成两组2个项:{1,4}+{-2,-3},{1,-2}+{4,-3}等等

我如何制作一个正确返回所有解决方案的算法来避免这个问题?
编辑:我应该补充一点,我希望使用尽可能高效的算法。O(len(arr)^4)对于我的任务来说太慢了…

首先请注意,在最坏的情况下,问题是
O(n^4)
,因为输出大小可能是
O(n^4)
(您正在寻找所有的解决方案,而不仅仅是二进制问题)

证明:
[-1]*(n/2)为例,扩展([1]*(n/2))
。您需要“选择”两个-1 w/o repeats-
(n/2)*(n/2-1)/2
可能性的实例,以及两个1 w/o repeats-
(n/2)*(n/2-1)/2
可能性的实例。这一共是
(n/2)*(n/2-1)*(n/2)*(n/2-1)/4
中的θ(n^4)

现在,我们明白了我们不能在最坏的情况下得到
O(n^2logn)
,我们可以得到下面的算法(伪代码),对于“好”的情况(几个相同的和),它应该更接近
O(n^2logn)
,并得到
O(n^4)
最坏的情况(如预期)

伪代码:

subsets <- all subsets of size of indices (not values!)
l <- empty list
for each s in subsets:
   #appending a triplet of (sum,idx1,idx2):
   l.append(( arr[s[0]] + arr[s[1]], s[0],s[1]))
sort l by first element (sum) in each tupple
for each x in l:
    binary search l for -x[0] #for the sum
    for each element y that satisfies the above:
          if x[1] != y[1] and x[2] != y[1] and x[1] != y[2] and x[2] != y[2]:
              yield arr[x[1]], arr[x[2]], arr[y[1]], arr[y[2]]

子集首先请注意,在最坏的情况下,问题是
O(n^4)
,因为输出大小可能是
O(n^4)
(您正在寻找所有解决方案,而不仅仅是二进制问题)

证明:
[-1]*(n/2)为例,扩展([1]*(n/2))
。您需要“选择”两个-1 w/o repeats-
(n/2)*(n/2-1)/2
可能性的实例,以及两个1 w/o repeats-
(n/2)*(n/2-1)/2
可能性的实例。这一共是
(n/2)*(n/2-1)*(n/2)*(n/2-1)/4
中的θ(n^4)

现在,我们明白了我们不能在最坏的情况下得到
O(n^2logn)
,我们可以得到下面的算法(伪代码),对于“好”的情况(几个相同的和),它应该更接近
O(n^2logn)
,并得到
O(n^4)
最坏的情况(如预期)

伪代码:

subsets <- all subsets of size of indices (not values!)
l <- empty list
for each s in subsets:
   #appending a triplet of (sum,idx1,idx2):
   l.append(( arr[s[0]] + arr[s[1]], s[0],s[1]))
sort l by first element (sum) in each tupple
for each x in l:
    binary search l for -x[0] #for the sum
    for each element y that satisfies the above:
          if x[1] != y[1] and x[2] != y[1] and x[1] != y[2] and x[2] != y[2]:
              yield arr[x[1]], arr[x[2]], arr[y[1]], arr[y[2]]
子集这是可行的

进口itertools

def foursum(arr):
  seen = {}
  for i in xrange(len(arr)):
      for j in xrange(i+1,len(arr)):
          if arr[i]+arr[j] in seen: seen[arr[i]+arr[j]].add((i,j))
          else: seen[arr[i]+arr[j]] = {(i,j)}
  for key in seen:
      if -key in seen:
          for (i,j) in seen[key]:
              for (p,q) in seen[-key]:
                  if i != p and i != q and j != p and j != q:
                      return True
  return False
编辑 我想这可以变得更像python,我对python的了解还不够。

这很有效

进口itertools

def foursum(arr):
  seen = {}
  for i in xrange(len(arr)):
      for j in xrange(i+1,len(arr)):
          if arr[i]+arr[j] in seen: seen[arr[i]+arr[j]].add((i,j))
          else: seen[arr[i]+arr[j]] = {(i,j)}
  for key in seen:
      if -key in seen:
          for (i,j) in seen[key]:
              for (p,q) in seen[-key]:
                  if i != p and i != q and j != p and j != q:
                      return True
  return False
编辑
我想这可以变得更像python,我对python的了解还不够。

编辑:当然,根据解决方案的大小,算法的时间复杂度至少应该是相同的

如果与n相比,可能的解决方案数量不是“大”,则

O(N^3)中的建议溶液:

找到所有元素的成对和,并构建一个和的NxN矩阵

对于该矩阵中的每个元素,构建一个结构,该结构将sumValue、row和column作为其字段

在1D数组中对所有这些
N^2
struct元素进行排序<代码>(在O(N^2 logN)时间内)

对于此数组中的每个元素
x
,对其伙伴
y
执行二进制搜索,以便
x+y=0(每次搜索的O(logn)

现在,如果您找到了合作伙伴
y
,请检查其行或列字段是否与元素
x
匹配。如果是这样,则在两个方向上依次迭代,直到其中一个方向不再有这样的y

如果您发现一些y没有与x共用的行或列,则增加计数(或打印解决方案)

由于行和列的长度为
N
,因此此迭代最多可以执行
2N个步骤


因此,该算法的总复杂度顺序应为
O(N^2*N)=O(N^3)
编辑:当然,根据解的大小,该算法的时间复杂度至少应为

如果与n相比,可能的解决方案数量不是“大”,则

O(N^3)中的建议溶液:

找到所有元素的成对和,并构建一个和的NxN矩阵

对于该矩阵中的每个元素,构建一个结构,该结构将sumValue、row和column作为其字段

在1D数组中对所有这些
N^2
struct元素进行排序<代码>(在O(N^2 logN)时间内)

对于此数组中的每个元素
x
,对其伙伴
y
执行二进制搜索,以便
x+y=0(每次搜索的O(logn)

现在,如果您找到了合作伙伴
y
,请检查其行或列字段是否与元素
x
匹配。如果是这样,则在两个方向上依次迭代,直到其中一个方向不再有这样的y

如果您发现一些y没有与x共用的行或列,则增加计数(或打印解决方案)

由于行和列的长度为
N
,因此此迭代最多可以执行
2N个步骤


因此,该算法的总复杂度顺序应为
O(N^2*N)=O(N^3)

允许输入元素多次使用是正常的。例如,给定输入(23 10-4-1),有效的解决方案是(31 0-4)和(0 0)

基本算法是O(n^2):使用两个嵌套循环,每个循环运行在输入中的所有项上,形成所有对的和,将和及其组件存储在某种字典(哈希表、AVL树)中。然后扫描对和,报告字典中也存在对和负数的任何四倍

如果你坚持不去杜普利