找到满足A + B = C + D的值的索引

时间:2016-09-19 06:19:20

标签: python algorithm python-2.7

使用Python 2.7处理下面的问题。发布我的代码并想知道是否有任何进一步的智能想法让它运行得更快?我认为可能会有一些想法首先对列表进行排序,并利用排序行为,但到目前为止还无法弄清楚。我的代码是O(n^2)时间复杂度。

问题

给定一个整数数组A,找到满足A + B = C + D的值的索引,其中A,B,C& D是数组中的整数值。找到四重组合的所有组合。

代码

from collections import defaultdict

sumIndex = defaultdict(list)

def buildIndex(numbers):
    for i in range(len(numbers)):
        for j in range(i+1,len(numbers)):
            sumIndex[numbers[i]+numbers[j]].append((i,j))

def checkResult():
    for k,v in sumIndex.items():
        if len(v) > 1:
            for i in v:
                print k, i

if __name__ == "__main__":
    buildIndex([1,2,3,4])
    checkResult()

输出,即和值,以及总和可能导致此值的索引,

5 (0,3)
5 (1,2)

3 个答案:

答案 0 :(得分:2)

考虑数组中所有元素相等的情况。然后我们事先知道答案,但仅打印结果将花费O(n^2)时间,因为有n*(n-1)/2个这样的对。所以我认为可以肯定地说,对于这个问题,没有比O(n^2)更复杂的方法。

答案 1 :(得分:1)

是的,它可以以复杂度小于O(n ^ 2)的方式完成。算法是:

  1. 创建一个重复数组假设indexArr []存储原始数组元素的索引,说origArr []。
  2. 使用具有复杂度O(nLogn)的算法以升序对origArr []进行排序。同样,在对origArr []进行排序时也会对indexArr []进行洗牌。
  3. 现在你必须在排序数组中找到对,你将运行2个循环找到所有可能的组合。假设您选择origArr[i] + origArr[i + 1] = sum.
  4. 现在,您将搜索iff sum <= origArr[n],其中n是数组的最后一个元素,即最大元素。此外,如果sum > origArr[n]那么你将打破内循环以及外循环,因为没有其他组合是可能的。
  5. 如果sum > origArr[j],您将打破内部循环,因为该总和不可能有其他组合。
  6. PS - 最糟糕的情况是O(n ^ 2)。

答案 2 :(得分:1)

使用itertools.combinations:

更快,更Pythonic方法
from collections import defaultdict
from itertools import combinations

def get_combos(l):
    d = defaultdict(list)
    for indices in combinations(range(len(l)),2):
        d[(l[indices[0]] + l[indices[1]])].append(indices)
    return {k:v for k,v in d.items() if len(v) > 1}

<小时/> 时间结果

                                             OP       this
len(l)=4, min(repeat=100, number=10000) | 0.09334  | 0.08050
len(l)=50, min(repeat=10, number=100)   | 0.08689  | 0.08996
len(l)=500, min(repeat=10, number=10)   | 0.64974  | 0.59553
len(l)=1000, min(repeat=3, number=3)    | 1.01559  | 0.83494
len(l)=5000, min(repeat=3, number=1)    | 10.26168 | 8.92959

计时代码

from collections import defaultdict
from itertools import combinations
from random import randint
from timeit import repeat


def lin_get_combos(l):
    sumIndex = defaultdict(list)
    for i in range(len(l)):
        for j in range(i+1,len(l)):
            sumIndex[l[i]+l[j]].append((i,j))
    return {k:v for k,v in sumIndex.items() if len(v) > 1}

def craig_get_combos(l):
    d = defaultdict(list)
    for indices in combinations(range(len(l)),2):
        d[(l[indices[0]] + l[indices[1]])].append(indices)
    return {k:v for k,v in d.items() if len(v) > 1}

l = []
for _ in range(4):
    l.append(randint(0,1000))
t1 = min(repeat(stmt='lin_get_combos(l)', setup='from __main__ import lin_get_combos, l', repeat=100, number=10000))
t2 = min(repeat(stmt='craig_get_combos(l)', setup='from __main__ import craig_get_combos, l', repeat= 100, number=10000))
print '%0.5f, %0.5f' % (t1, t2)

l = []
for _ in range(50):
    l.append(randint(0,1000))
t1 = min(repeat(stmt='lin_get_combos(l)', setup='from __main__ import lin_get_combos, l', repeat=10, number=100))
t2 = min(repeat(stmt='craig_get_combos(l)', setup='from __main__ import craig_get_combos, l', repeat= 10, number=100))
print '%0.5f, %0.5f' % (t1, t2)

l = []
for _ in range(500):
    l.append(randint(0,1000))
t1 = min(repeat(stmt='lin_get_combos(l)', setup='from __main__ import lin_get_combos, l', repeat=10, number=10))
t2 = min(repeat(stmt='craig_get_combos(l)', setup='from __main__ import craig_get_combos, l', repeat= 10, number=10))
print '%0.5f, %0.5f' % (t1, t2)

l = []
for _ in range(1000):
    l.append(randint(0,1000))
t1 = min(repeat(stmt='lin_get_combos(l)', setup='from __main__ import lin_get_combos, l', repeat=3, number=3))
t2 = min(repeat(stmt='craig_get_combos(l)', setup='from __main__ import craig_get_combos, l', repeat= 3, number=3))
print '%0.5f, %0.5f' % (t1, t2)

l = []
for _ in range(5000):
    l.append(randint(0,1000))
t1 = min(repeat(stmt='lin_get_combos(l)', setup='from __main__ import lin_get_combos, l', repeat=3, number=1))
t2 = min(repeat(stmt='craig_get_combos(l)', setup='from __main__ import craig_get_combos, l', repeat= 3, number=1))
print '%0.5f, %0.5f' % (t1, t2)