题目:构建乘积数组
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]*A[1]*…*A[i-1]*A[i+1]*…*A[n-1]。不能使用除法。
开始思考这个问题:
因为不许用除法,我就构建了两个数组保存中间结果:
mid_1 = [1, A[0], A[0]A[1], A[0]A[1]A[2], …, A[0]A[1],…A[N-1]]
mid_2 = [A[1]A[2]…A[N-1], A[2]A[3]…A[N-1], A[3]…A[N-1], A[4]A[5]…A[N-1],… 1 ]$
构建完这两个数组以后,
B[i] = mid_1[i] *mid_2[i]
反正这样写挺笨的,但还是可以通过的嘛~
def multiply(A):
N = len(A)
if N ==0 or N ==1:
return []
B = []
mid_1 =[]
mid_2 =[]
# 每个数组的长度为 N
for i in range(0,N):
tmp = 1
for j in range(i):
tmp*=A[j]
mid_1.append(tmp)
tmp = 1
for k in range(i+1,N):
tmp*=A[k]
mid_2.append(tmp)
for i in range(N):
B[i] =mid_1[i]*mid_2[i]
return B
后来发现呢,这两个中间数组其实可以不要啊,只要把B[i]初始化为1分成两部分算就好了
左边: B[i] *= A[left] , left的范围是 [0, i-1]
接着乘右边: B[i] *= A[right], right 的范围是 [i+1, N-1]
def multiply2(A):
N = len(A)
if N==1 or N==0:
return []
# 避坑指南:为了防止index越界,在知道数组大小时可以全部初始化
# 这里对元素做乘法运算,初始化为1
# 对于要做加法运算的数组可以初始化为0
B = [1 for i in range(N)]
for i in range(N):
for left in range(i):
B[i]*=A[left]
for right in range(i+1,N):
B[i] *=A[right]
return B
但是这里还是有一个问题,就是在计算B的过程中存在很多重复运算。B[i] 中存在B[i-1]中计算过的很多部分.
比如从上图一个长度为5的数组的计算图可以看出来每一行都存在重复。
1的左边每次下面一行(第i行)都比上面一行多一个A[i-1]
1的右边每次上面一行 (第i行) 都比下面一行多一个A[i+1]
于是可以这样计算:
左边自上而下:
i 从1到N-1, B[i] = B[i-1]*A[i-1]
右边自下而上:tmp=1
i 从N-2到0,tmp *= A[i+1] , B[i] *=tmp
def multiply(A):
N = len(A)
if N == 0 or N ==1:
return []
B =[1 for i in range(N)]
for i in range(1,N):
B[i] = B[i-1]*A[i-1]
tmp = 1
for i in range(N-2,-1,-1):
tmp *= A[i+1]
B[i]*=tmp
return B