问题
给出了由N个整数组成的零索引数组A.该数组的均衡指数是任何整数P,使得0 ≤ P < N
和较低指数的元素之和等于较高指数的元素之和。
A[0] + A[1] + ... + A[P−1] = A[P+1] + ... + A[N−2] + A[N−1].
假设零元素的总和等于0.如果P = 0
或P = N−1
,可能会发生这种情况。
N的范围:[0 ... 100,000]
。
元素范围:[−2,147,483,648 ... 2,147,483,647]
。
复杂性:最坏情况时间O(N)
我的5分钟解决方案
这是直观的解决方案,通过计算公式性能为O(N^2)
,因为它为每次迭代求和所有数组,并且它不适用于大型条目。
def solution(A):
result = []
for i in xrange(len(A)):
if sum(A[:i]) == sum(A[i+1:]):
result.append(i)
if result == []:
return -1
return result
最佳解决方案
此解决方案为O(N)
。有人可以解释这个解决方案背后的逻辑。
def equi(A):
result = []
x=1
i=1
r=sum(A)
for e in A:
i-=1
r-=2*e
if -e==r:
result.append(-i)
return result
答案 0 :(得分:3)
我相信你发布的解决方案根本不起作用,反正很难理解。 所以我的看法就是这样:
def equi(v):
left_sum = 0 # sum(v[:p]) at all times.
right_sum = sum(v) # sum(v[p+1:]) at all times.
for i in xrange(len(v)):
right_sum -= v[i]
if left_sum == right_sum:
return i # your p.
left_sum += v[i]
return -1 # Because, there may not be an equilibrium index at all.
基本上,不是在循环的每次迭代中重新计算sum(左侧)和sum(右侧),而是可以通过简单的数学计算它们。
在某种程度上说明了一个大小为n的数组:
pos1 = i
left_sum1 = v[0] + v[1] + ... + v[i-1]
right_sum1 = v[i+1] + v[i+2] + ... + v[n-1]
现在让我们前进一步,检查一下我们应该拥有什么:
pos2 = i+1
left_sum2 = v[0] + v[1] + ... + v[i]
right_sum2 = v[i+2] + v[i+2] + ... + v[n-1]
现在,改变了什么?
left_sum2 - left_sum1 = v[i]
right_sum2 - right_sum1 = -v[i+1]
这可能会令人困惑,但应该明白,通过添加和减去先前的值,可以通过某种方式获得左侧和右侧的总和。
答案 1 :(得分:1)
O(n)解决方案有点过于聪明并且有些混淆,但它的工作正常。我用有意义的变量名称重写了它,并移动了一些东西,使它更清楚它是如何工作的。
def equilibriums(A): # line 1
result = [] # line 2
difference = sum(A) # line 3
for p in range(len(A)): # line 4
difference -= 2*A[p] # line 5
if -A[p] == sum_of_tail: # line 6
result.append(p) # line 7
return result # line 8
现在解释一下。让
left = 0,
right = A[0] + A[1] + ... + A[N-2] + A[N-1] = sum(A), and
difference = right - left = sum(A) - 0 = sum(A) # <-- explains line 3
从A[0]
移除right
并添加到left
时,difference
会降低2*A[0]
。如果A[1]
从right
移至left
,则difference
会降低2*A[1]
。每当移动元素A[p]
时,difference
都会降低2*A[p]
。这解释了第4和第5行。
现在,在均衡指数P,我们有:
A[0] + A[1] + ... + A[P−1] = A[P+1] + ... + A[N−2] + A[N−1] # definition
= A[P+1] + ... + A[N−2] + A[N−1] + A[P] - A[P] # add A[P]-A[P]
= A[P] + A[P+1] + ... + A[N−2] + A[N−1] - A[P] # rearrange
\---- but this = left ---/ \--------- and this = right --------/
,或者
left = right - A[P]
和
difference = right - left # definition
= right - (right - A[P]) # substitute
= A[P] # simplify
如果我们将A[P]
从right
移至left
,则difference
会降低2*A[P]
,现在
difference = A[P] - 2*A[P] = -A[P]
也就是说,当平衡点从right
移动到left
时,difference
从A[P]
变为-A[P]
。因此,如果difference == -A[P]
,则P
是均衡指数。这解释了第6行的测试。
注意,算法并不真正需要left
和right
。它们只是用于解释。
equilibriums([1,2,3,0,1,0,0,0,0,1,6]) ==> returns [5, 6, 7, 8]
答案 2 :(得分:0)
另一种方法如下:
考虑我们在任务开始时所知道的内容 - 我们知道输入的长度,即len(A)
,我们知道输入的总和即sum(A)
,我们也知道没有先前的金额已计算出来。因此,这些成为我们的初始变量
sumA, prevSum, n = sum(A), 0, len(A)
接下来让我们考虑每次迭代会发生什么。我们声明一个变量,例如rem
这是(sumA - prevSum -A[i])
的值。本质上,在每次迭代中,我们希望从数组的总和中删除前一个总和(prevSum
或leftSum
),并删除当前值。
然后我们检查是否rem == prevSum
。如果这是True,我们返回索引,如果为false,我们重复此循环,直到此时检查了数组中的所有元素,我们返回一个Falsy值。
此代码可用here