给定一个长度为N的整数数组(含正数和负数),只允许用乘法,不能用除法,计算(N-1)个数的组合中乘积最大的一组。
解法 1
暴力写法很容易就可以写出来,就是把所有的(N-1)个数组合找出来,分别计算它们的乘积,并计算大小。由于总共有N个(N-1)个数的组合,总的时间赋值度是O(N*N)。
array = [i for i in range(-8,8)]
ans = -2**31
def product(nums): # 乘积
res = 1
for i in range(len(nums)):
res *= nums[i]
return res
def conbination(track, start, array): # 组合
global ans
if len(track) == len(array)-1:
ans = max(ans, product(track))
return
for i in range(start, len(array)):
track.append(array[i])
conbination(track,i+1,array)
track.pop()
conbination([],0,array)
print(ans)
暴力法还有一种做法:就是用N个数的乘积除以整数数组中的每个数。但这种做法的前提条件是整数数组不能含有0,因为含有0的化N个数的乘积就会等于0。
解法 2
解法1显然不是最好的解法。在计算机科学中,时间和空间往往是一对矛盾体,不过这里有一个折中的方法。可以通过“空间换时间”或时间换空间的策略来达到优化某方面的目的。在这里是否可以通过“空间换时间”来降低时间复杂度呢?计算(N-1)个数的组合,假设第i个(0<=i<=N-1)个元素被排除在乘积之外。
设array[]为初始数组,s[i]为前i个元素的乘积其中1<=i<=N,s[0] = 1为边界条件,那么有s[i] = s[i-1]*array[i-1]。设t[i]为数组后(N-i)个元素的乘积。那么t[i] = t[i+1]*array[i],其中1<=i<=N,t[N+1] = 1为边界条件。那么设p[i]为数组除第i个元素外,其他N-1个元素的乘积,即有:
p[i] = s[i-1]*t[i+1]
该算法的时间复杂度为O(N)。
array = [i for i in range(-8,8)]
n = len(array)
s, t, p = [1]+[0]*(n), [0]*(n) + [1], [0]*(n)
# s[i]表示前i个元素的乘积
for i in range(1,n+1):
s[i] = s[i-1]*array[i-1]
# t[i]表示数组后(N-i)个元素的乘积
for i in range(n-1,-1,-1):
t[i] = t[i+1]*array[i]
# p[i]为数组除第i个元素外,其他N-1个元素的乘积
for i in range(n):
p[i] = s[i-1]*t[i+1]
print(max(p))
解法 3
可以通过分析正负符号来进一步减少解答问题的计算量。我认为这是在找规律。假设N个整数的乘积为P。针对P的正负性进行如下分析(其中A(N-1)表示N-1个数的组合,P(N-1)表示N-1个数的组合乘积)
P = 0
那么,数组中至少包括一个0。假设除去一个0之外,其他N-1个数得乘积为Q,根据Q的正负号来进行判断:
- Q为0 说明数组中至少有两个0,所以返还的乘积为0
- Q为正数 返还Q
- Q 为负数 返还0
P 为负数
根据“负负的正”的乘法性质,从N个数中去掉一个负数,使得P(N-1)为正数。这个去掉的负数的绝对值是最小的。
P为正数
如果数组中存在正数,那么去掉最小的正数值,否则去掉绝对值最大的负数。
时间复杂度为O(N)。
array = [i for i in range(-8,8)]
Num0 = [] # 0的个数,直接保存索引
NumNagative = [] # 负数的个数,直接保存索引
NumPositive = [] # 正数的个数,直接保存索引
for i in range(len(array)):
if array[i] == 0:
Num0.append(i)
elif array[i] < 0:
NumNagative.append(i)
else:
NumPositive.append(i)
# 如果P = 0
if len(Num0) >= 1:
if len(Num0) > 1 or len(NumNagative)%2 == 1:
print(0)
else:
P = 1
for i in range(len(array)):
if i != Num0[-1]:
P *= array[i]
print(P)
# 如果P为负数
elif len(NumNagative)%2 == 1:
# 找到NumNagative绝对值的最小的值
AbsMin = array[NumNagative[0]]
for i in range(1,len(NumNagative)):
if abs(array[NumNagative[i]]) <= abs(AbsMin):
AbsMin = array[NumNagative[i]]
P = 1
for i in range(len(array)):
if array!=AbsMin:
P *= array[i]
print(P)
# P为正数
else:
if len(NumPositive)!= 0:
NumMin = array[NumPositive[0]]
for i in range(1,len(NumPositive)):
if NumMin >= array[NumPositive[i]]:
NumMin = array[NumPositive[i]]
P = 1
for i in range(len(array)):
if array != NumMin:
P *= array[i]
print(P)
else:
AbsMax = array[NumNagative[0]]
for i in range(1, len(NumNagative)):
if abs(array[NumNagative[i]]) >= abs(AbsMax):
AbsMax = array[NumNagative[i]]
P = 1
for i in range(len(array)):
if array != AbsMax:
P *= array[i]
print(P)