我想在O(log N)
时间使用分而治之的方法找到数组中的最大元素。我在planet-source-code找到了一份工作代码。我把它翻译成Python如下:
def largest(arr,i,j):
global max1
global max2
if i == j:
max1 = arr[i]
else:
if i == j-1:
max1 = arr[i] if arr[i] > arr[j] else arr[j]
else:
mid = (i+j)/2
largest(arr,i,mid)
max2 = max1
largest(arr,mid+1,j)
if max2 > max1:
max1 = max2
当我使用数组[98,5,4,3,2,76,78,92]
时,将代码调用为
max1 = arr[0]
largest(arr,1,8)
我收到了一个越界列表索引错误。但是,C代码返回正确的结果98.任何人都可以发现我在做什么错误吗?
答案 0 :(得分:3)
对于一般的未排序数组,您永远不会在O(n)时间内找到max
。非常简单的证明:如果你在不到O(n)的时间内完成它,那么对于一个足够大的数组,你没有足够的时间来检查每个元素。因此,攻击者可以将最大值放在您未检查的元素中,从而使您的算法不正确。
原始代码的优点是使用少于2n次比较同时找到两者最大值和最小值(正如天真的实现所做的那样) - 它使用大约1.5n的比较,因为它仅执行有两个要素的比较。使用它只能找到最大值没有任何好处:你最好在Python中使用max(arr)
(由于没有函数调用开销,它也会更快)。
原始代码将值存储在a[1]
到a[n]
中,这需要一个大小为n+1
的数组。因此,您应该将虚拟元素放在第一个位置。
但是,更有问题的是,您的翻译不正确。原始使用全局变量来实现多值返回(这是一种令人难以置信的hacky方式),以及用于保存旧全局变量的局部变量。由于您同时将max1
和max2
设为全局,因此该函数无论如何都无法生成正确的答案。
对Python的正确翻译将使用带有元组的直接多值返回:
def minmax(arr, i, j):
if i==j:
return arr[i], arr[i]
elif i==j-1:
if arr[i] < arr[j]:
return arr[i], arr[j]
else:
return arr[j], arr[i]
else:
mid = (i+j)//2
min1, max1 = minmax(arr, i, mid)
min2, max2 = minmax(arr, mid+1, j)
if min2 < min1: min1 = min2
if max2 > max1: max1 = max2
return min1, max1
答案 1 :(得分:1)
你最终会有一个函数调用
largest(arr, 7,8)
然后你的代码
max1 = arr[i] if arr[i] > arr[j] else arr[j]
将尝试索引arr [j] = arr [8] 这是超出界限,因为Python枚举了0-7的向量,而不是1-8。
顺便说一下,我认为你没有O(log N)算法,因为所有元素必须至少扫描一次以找到最大元素,导致O(N)。