我看了几个网站上的几个讨论,但没有一个给我一个解决方案。 这段代码运行时间超过5秒:
for i in xrange(100000000):
pass
我正在研究整数优化问题,我必须使用 O(n log n)算法编辑:一个O(n²/ 4)算法,其中n代表所有矩阵'项,即在下面的代码中,n * m = 10000.因此,对于具有10000个元素的矩阵100 * 100,它将导致近25000000次迭代...... 。 它的代码可以总结如下:
m = 100
n = 100
for i in xrange(m):
for j in xrange(n):
for i2 in xrange(i + 1, m):
for j2 in xrange(j + 1, n):
if myarray[i][j] == myarray[i2][j2] and myarray[i2][j] == myarray[i][j2]:
return [i, j], [i2, j2]
我应该放弃Python并返回Java或C?
我使用Python 2.7并且Psyco不可用。 PyPy不支持Tkinter开箱即用,我正在使用Tkinter。
那么,他们会提高循环速度吗?还有其他解决方案吗?
答案 0 :(得分:15)
不是最漂亮的编码风格,但绝望的时候需要绝望的编码。尝试将嵌套的嵌套循环转换为一个大的生成器表达式:
try:
i,j,i2,j2 = ((i,j,i2,j2)
for i in xrange(m)
for j in xrange(n)
for i2 in xrange(i + 1, m)
for j2 in xrange(j + 1, n)
if myarray[i][j] == myarray[i2][j2] and
myarray[i2][j] == myarray[i][j2]).next()
return [i,j],[i2,j2]
except StopIteration:
return None
已更新为使用内置next
和product
以及Py3 range
而不是xrange
:
from itertools import product
match = next(((i,j,i2,j2)
for i, j in product(range(m), range(n))
for i2, j2 in product(range(i+1, m), range(j+1, n))
if myarray[i][j] == myarray[i2][j2] and
myarray[i2][j] == myarray[i][j2]), None)
if match is not None:
i,j,i2,j2 = match
return [i,j],[i2,j2]
else:
return None
答案 1 :(得分:11)
您仍然可以使用python表示法,并使用Cython项目获得C的速度。 第一步是在C循环中转换循环:它是通过键入循环中使用的所有变量自动完成的:
cdef int m = 100
cdef int n = 100
cdef int i, j, i2, j2
for i in xrange(m):
for j in xrange(n):
for i2 in xrange(i + 1, m):
for j2 in xrange(j + 1, n):
对于下一部分,如果myarray是纯C数组,那么没有丰富的python comparaison或数组访问会更好。使用你的python数组,你可以通过本机比较来删除丰富的比较(如果你的数组有两倍):
cdef double a, b, c, d
a = myarray[i][j]
b = myarray[i2][j2]
c = myarray[i2][j]
d = myarray[i][j2]
if a == b and c == d:
return [i, j], [i2, j2]
您可以通过运行cython -a yourfile.pyx
,然后打开yourfile.html
生成来查看优化的进展情况。您将看到Cython如何优化您的代码,并消除了Python开销。
答案 2 :(得分:2)
很抱歉告诉您,但这不是优化问题。无论您选择哪种语言或实现,此算法在最差和平均情况下都不是O(n*log n)
。您可能希望阅读how the Big-O notation works并开发出更好的算法。
答案 3 :(得分:1)
抱歉生成器expr不起作用。这是一个不同的方案,首先计算所有类似的值,然后查找矩形组:
from collections import defaultdict
from itertools import permutations
def f3(myarray):
tally = defaultdict(list)
for i,row in enumerate(myarray):
for j,n in enumerate(row):
tally[n].append((i,j))
# look for rectangular quads in each list
for k,v in tally.items():
for quad in permutations(v,4):
# sort quad so that we can get rectangle corners
quad = sorted(quad)
(i1,j1),(i2,j2) = quad[0], quad[-1]
# slice out opposite corners to see if we have a rectangle
others = quad[1:3]
if [(i1,j2),(i2,j1)] == others:
return [i1,j1],[i2,j2]
答案 4 :(得分:1)
我在你的代码中看了好几次,如果我说对了,你用两个不同的角标记你的矩形。我很抱歉,如果我的答案更多的是澄清你的立场,那么就是一个真正的答案。
<强>答-部分:强>: 如果您正在寻找合适的算法,请考虑使用扫描线算法。我为“最大的矩形解决方案”找到了一个示例here @SO。
我的问题是,你到底在寻找什么?
我还必须指出,保罗和你的解决方案会产生不同的结果,因为保罗认为角落标有相同的值而你假设,角落是通过两个不同的值标记的!
我花时间和自由用一个丑陋的c&amp; p脚本来说明它: 它通过创建2D字段并将其填充来比较两种算法 string.lowercase chars并将角转换为大写字符。
from random import choice
from string import lowercase
from collections import defaultdict
from itertools import permutations
from copy import deepcopy
m,n = 20, 20
myarray = [[choice(lowercase) for x in xrange(m)] for y in xrange(n)]
def markcorners(i,j,i2,j2):
myarray[i][j] = myarray[i][j].upper()
myarray[i2][j] = myarray[i2][j].upper()
myarray[i2][j2] = myarray[i2][j2].upper()
myarray[i][j2] = myarray[i][j2].upper()
def printrect():
for row in myarray:
print ''.join(row)
print '*'*m
def paul_algo():
tally = defaultdict(list)
for i,row in enumerate(myarray):
for j,n in enumerate(row):
tally[n].append((i,j))
# look for rectangular quads in each list
for k,v in tally.items():
for quad in permutations(v,4):
# sort quad so that we can get rectangle corners
quad = sorted(quad)
(i1,j1),(i2,j2) = quad[0], quad[-1]
# slice out opposite corners to see if we have a rectangle
others = quad[1:3]
if [(i1,j2),(i2,j1)] == others:
markcorners(i1,j1,i2,j2)
def xavier_algo():
for i in xrange(m):
for j in xrange(n):
for i2 in xrange(i + 1, m):
for j2 in xrange(j + 1, n):
if myarray[i][j] == myarray[i2][j2] and myarray[i2][j] == myarray[i][j2]:
markcorners(i,j,i2,j2)
savearray = deepcopy(myarray)
printrect()
xavier_algo()
printrect()
myarray = deepcopy(savearray)
paul_algo()
printrect()