Python θ(n**2)和θ(n*lgn)算法执行不正确
我正在读算法简介,并试图完成书中的练习 在练习4.1-3中 4.1-3 在您自己的计算机上实现最大子阵列问题的蛮力算法和递归算法。n0给出的交叉问题大小是多少 递归算法打败蛮力算法的点?那么, 将递归算法的基本情况更改为使用蛮力算法 当问题大小小于n0时。这会改变交叉点吗 我根据书中的伪代码编写了这两个算法。但是,我的代码一定有问题,因为第二个代码被设计为θ(n*lgn)并且应该运行得更快,它总是比第一个θ(n**2)代码运行得慢。我的代码如下所示 def find_maximum_subarray_bf(a): #bf for brute force p1 = 0 l = 0 # l for left r = 0 # r for right max_sum = 0 for p1 in range(len(a)-1): sub_sum = 0 for p2 in range(p1, len(a)): sub_sum += a[p2] if sub_sum > max_sum: max_sum = sub_sum l = p1 r = p2 return l, r, max_sum def find_maximum_subarray_dc(a): #dc for divide and conquer # subfunction # given an arrary and three indics which can split the array into a[l:m] # and a[m+1:r], find out a subarray a[i:j] where l \leq i \less m \less j \leq r". # according to the definition above, the target subarray must # be combined by two subarray, a[i:m] and a[m+1:j] # Growing Rate: theta(n) def find_crossing_max(a, l, r, m): # left side # ls_r and ls_l indicate the right and left bound of the left subarray. # l_max_sum indicates the max sum of the left subarray # sub_sum indicates the sum of the current computing subarray ls_l = 0 ls_r = m-1 l_max_sum = None sub_sum = 0 for j in range(m+1)[::-1]: # adding elements from right to left sub_sum += a[j] if sub_sum > l_max_sum: l_max_sum = sub_sum ls_l = j # right side # rs_r and rs_l indicate the right and left bound of the left subarray. # r_max_sum indicates the max sum of the left subarray # sub_sum indicates the sum of the current computing subarray rs_l = m+1 rs_r = 0 r_max_sum = None sub_sum = 0 for j in range(m+1,len(a)): sub_sum += a[j] if sub_sum > r_max_sum: r_max_sum = sub_sum rs_r = j #combine return (ls_l, rs_r, l_max_sum+r_max_sum) # subfunction # Growing Rate: should be theta(nlgn), but there is something wrong def recursion(a,l,r): # T(n) if r == l: return (l,r,a[l]) else: m = (l+r)//2 # theta(1) left = recursion(a,l,m) # T(n/2) right = recursion(a,m+1,r) # T(n/2) crossing = find_crossing_max(a,l,r,m) # theta(n) if left[2]>=right[2] and left[2]>=crossing[2]: return left elif right[2]>=left[2] and right[2]>=crossing[2]: return right else: return crossing #back to master function l = 0 r = len(a)-1 return recursion(a,l,r) if __name__ == "__main__": from time import time a = [100,-10,1,2,-1,4,-6,2,5] a *= 2**10 time0 = time() find_maximum_subarray_bf(a) time1 = time() find_maximum_subarray_dc(a) time2 = time() print "function 1:", time1-time0 print "function 2:", time2-time1 print "ratio:", (time1-time0)/(time2-time1) def find_maximum_subarray_bf(a):#蛮力的bf p1=0 l=0#l表示左侧 r=0#r表示右侧 最大和=0 对于范围内的p1(透镜(a)-1): 次和=0 对于范围内的p2(p1,len(a)): 子总和+=a[p2] 如果子总和>最大总和: 最大和=次和 l=p1 r=p2 返回l,r,最大和 def find_maximum_subarray_dc(a):#用于分治的dc #子功能 #给定一个数组和三个可以将数组拆分为[l:m]的指示符 #和a[m+1:r],找出子阵a[i:j],其中l\leq i\less m\less j\leq r”。 #根据上面的定义,目标子阵列必须 #由两个子阵a[i:m]和a[m+1:j]组合而成 #增长率:θ(n) def find_crossing_max(a、l、r、m): #左侧 #ls_r和ls_l表示左子阵列的右边界和左边界。 #l_max_sum表示左子阵列的最大和 #sub_sum表示当前计算子阵列的和 ls_l=0 ls_r=m-1 l_max_sum=无 次和=0 对于范围(m+1)[::-1]:#从右向左添加元素 子_和+=a[j] 如果sub_sum>l_max_sum: l_max_sum=子_sum ls_l=j #右侧 #rs_r和rs_l表示左子阵列的右边界和左边界。 #r_max_sum表示左子数组的最大和 #sub_sum表示当前计算子阵列的和 rs_l=m+1 rs_r=0 r_max_sum=无 次和=0 对于范围(m+1,len(a))内的j: 子_和+=a[j] 如果sub_sum>r_max_sum: r_max_sum=次和 rs_r=j #结合 返回值(ls\u l、rs\u r、l\u max\u sum+r\u max\u sum) #子功能 #增长率:应该是θ(nlgn),但有点不对劲 def递归(a,l,r):#T(n) 如果r==l: 返回(l,r,a[l]) 其他: m=(l+r)//2#θ(1) 左=递归(a,l,m)#T(n/2) 右=递归(a,m+1,r)#T(n/2) 交叉=找到交叉点最大值(a,l,r,m)#θ(n) 如果左[2]>=右[2]和左[2]>=交叉[2]: 左转 elif right[2]>=左[2]和right[2]>=交叉点[2]: 返回权 其他: 回程交叉口 #返回主控功能 l=0 r=len(a)-1 返回递归(a,l,r) 如果名称=“\uuuuu main\uuuuuuuu”: 从时间导入时间 a=[100,-10,1,2,-1,4,-6,2,5] a*=2**10 time0=时间() 查找\u最大\u子阵列\u bf(a) time1=时间() 查找\u最大\u子阵列\u dc(a) time2=时间() 打印“功能1:”,时间1-0 打印“功能2:”,时间2-1 打印“比率:”,(time1-time0)/(time2-time1)Python θ(n**2)和θ(n*lgn)算法执行不正确,python,algorithm,python-2.7,Python,Algorithm,Python 2.7,我正在读算法简介,并试图完成书中的练习 在练习4.1-3中 4.1-3 在您自己的计算机上实现最大子阵列问题的蛮力算法和递归算法。n0给出的交叉问题大小是多少 递归算法打败蛮力算法的点?那么, 将递归算法的基本情况更改为使用蛮力算法 当问题大小小于n0时。这会改变交叉点吗 我根据书中的伪代码编写了这两个算法。但是,我的代码一定有问题,因为第二个代码被设计为θ(n*lgn)并且应该运行得更快,它总是比第一个θ(n**2)代码运行得慢。我的代码如下所示 def find_maximum_subarr
首先,暴力中的一个错误:
for p1 in range(len(a)-1):
这应该是range(len(a))
[或xrange
],也就是说,它找不到[-12,10]
的最大子数组
现在,递归:
def find_crossing_max(a, l, r, m):
# left side
# ls_r and ls_l indicate the right and left bound of the left subarray.
# l_max_sum indicates the max sum of the left subarray
# sub_sum indicates the sum of the current computing subarray
ls_l = 0
ls_r = m-1
l_max_sum = None
sub_sum = 0
for j in range(m+1)[::-1]: # adding elements from right to left
您正在将所有索引检查为0,但只应将索引检查为l
。使用xrange(m,l-1,-1)
对于右边的和,模拟值成立,您应该只检查r
,因此xrange(m+1,r+1)
此外,最大子数组的和与索引的初始值对于左侧部分是可疑的,对于右侧是错误的
对于左边的部分,我们从一个空和开始,但必须包括a[m]
。这可以通过设置l\u max\u sum=None
开始,或者通过设置l\u max\u sum=a[m]来实现
并让j
忽略索引m
。无论哪种方式,ls\u l
的初始值不应为0
,而ls\u r
的初始值不应为m-1
ls\u r
必须为m
,如果ls\u l
的初始值为m+1
de>为None
,如果l\u max\u sum
以a[m]
开头,则为m
对于正确的部分,r\u max\u sum
必须从0开始,而r\u r
最好从m
开始(虽然这并不重要,但它只会给你错误的索引)。如果右边的和都不是非负的,那么正确的和应该是0
,而不是负和中的最大值
在递归中,我们在
left = recursion(a,l,m) # T(n/2)
包括a[m]
在内的总和已经在find\u crossing\u max
中进行了处理或优化,因此可以
left = recursion(a,l,m-1)
但是,我们还必须在递归中处理可能性r
,重复性很小,所以我就让这种情况继续下去
因为你总是穿越整个世界
left = recursion(a,l,m-1)
def find_maximum_subarray_bf(a): #bf for brute force
p1 = 0
l = 0 # l for left
r = 0 # r for right
max_sum = 0
for p1 in xrange(len(a)):
sub_sum = 0
for p2 in xrange(p1, len(a)):
sub_sum += a[p2]
if sub_sum > max_sum:
max_sum = sub_sum
l = p1
r = p2
return l, r, max_sum
def find_maximum_subarray_dc(a): #dc for divide and conquer
# subfunction
# given an arrary and three indices which can split the array into a[l:m]
# and a[m+1:r], find out a subarray a[i:j] where l \leq i \less m \less j \leq r".
# according to the definition above, the target subarray must
# be combined by two subarray, a[i:m] and a[m+1:j]
# Growing Rate: theta(n)
def find_crossing_max(a, l, r, m):
# left side
# ls_r and ls_l indicate the right and left bound of the left subarray.
# l_max_sum indicates the max sum of the left subarray
# sub_sum indicates the sum of the current computing subarray
ls_l = m+1
ls_r = m
l_max_sum = None
sub_sum = 0
for j in xrange(m,l-1,-1): # adding elements from right to left
sub_sum += a[j]
if sub_sum > l_max_sum:
l_max_sum = sub_sum
ls_l = j
# right side
# rs_r and rs_l indicate the right and left bound of the left subarray.
# r_max_sum indicates the max sum of the left subarray
# sub_sum indicates the sum of the current computing subarray
rs_l = m+1
rs_r = m
r_max_sum = 0
sub_sum = 0
for j in range(m+1,r+1):
sub_sum += a[j]
if sub_sum > r_max_sum:
r_max_sum = sub_sum
rs_r = j
#combine
return (ls_l, rs_r, l_max_sum+r_max_sum)
# subfunction
# Growing Rate: theta(nlgn)
def recursion(a,l,r): # T(n)
if r == l:
return (l,r,a[l])
else:
m = (l+r)//2 # theta(1)
left = recursion(a,l,m) # T(n/2)
right = recursion(a,m+1,r) # T(n/2)
crossing = find_crossing_max(a,l,r,m) # theta(r-l+1)
if left[2]>=right[2] and left[2]>=crossing[2]:
return left
elif right[2]>=left[2] and right[2]>=crossing[2]:
return right
else:
return crossing
#back to master function
l = 0
r = len(a)-1
return recursion(a,l,r)
if __name__ == "__main__":
from time import time
from sys import argv
from random import randint
alen = 100
if len(argv) > 1:
alen = int(argv[1])
a = [randint(-100,100) for i in xrange(alen)]
time0 = time()
print find_maximum_subarray_bf(a)
time1 = time()
print find_maximum_subarray_dc(a)
time2 = time()
print "function 1:", time1-time0
print "function 2:", time2-time1
print "ratio:", (time1-time0)/(time2-time1)