编程练习思考[3]---leetcode--Maximum Product Subarray

QUESTION问题

Find the contiguous subarray within an array (containing at least one number) which has the largest product.
For example, given the array [2,3,-2,4],the contiguous subarray [2,3] has the largest product = 6.


SOLUTION

# 复杂版本
#开始想了一个复杂版本,从最大size的数组出发,进行遍历。
比如数组长度为5,那么我就
1 先计算长度为4的所有数组的积
2 再计算长度为3的所有数组的积
....
3 逐步计算更新我的maxProduct值。
这样做遍历次数有,1+2+3+...+len(arr)=O(n的平方)的复杂度

# def maxProduct(A):
#     #k=len(A)
#     #A=[2,3,-2,4]
#     prd=1
#     max=-10000
#     for size in range(0,len(A)):#4-->1
#         size=len(A)-size
#         for pos in range(0,len(A)-size+1): #3的时候
#             prd=1
#             start=pos
#             for k in range(size):
#                 prd*=A[start]
#                 start+=1
#             if prd>max:
#                 max=prd
#     return max

后来才知道这叫动态规划,只需要进行一次遍历就可以解决问题了。
最基本的思想就是,首先区分有没有0的情况
1 如果一段时间内我们的连续积没有0出现,那么我们就一直乘。------------------------------------------------------------------------------------------------
  因为有正有负,所以连乘积也是有正有负的,正最大的数字有可能乘个负数就变成绝对值更大的负数,而绝对值很大的负数轮到乘以下一个负数时就又变成最大值了,他们都是potentialMaxProduct的有力争夺者,而且互相生成互相依赖。因此我们在连乘中要保存两个变量:一个是上限的连乘积upperPrd,一个是下限的连乘积lowerPrd(Prd就是Product,积的意思),这两个积自己可能会进行更新(比如下面的(3)步骤),也都有可能在下一个数的时候进行相互转换,产生更大的值。
  比方说1  2  -3  4  -5  6
  1)当我们计算到2的时候,我们算得upperPrd为2,lowerPrd为初始值1,
  2)当计算到-3的时候,我们算得upperPrd为2,lowerPrd为初始值-6,
  3)当计算到4的时候, 我们算得upperPrd更新为4,lowerPrd为初始值-24 
     (这里前一个upperPrd为1*2=2,但是隔了个负数-3后,我遇到了4,由于4>2,所以把当前上线连续积值更新成了4)
  4)当计算到-5的时候, 我们算得upperPrd为4,lowerPrd更新为(-5)*(-24)=120
  ...
  写成代码就是这样的。

    for i in A:
        if(i>0):
            upperPrd=max(upperPrd*i,i) #向上抽取,
                                       #如果前连续积*i>当前值,那么连续积就继续乘下去upperPrd=upperPrd*i
                                       #反之,如果i自己比较大,那么就从i开始为upperPrd新立门户         
            lowerPrd=lowerPrd*i            
            maxPrd=max(upperPrd,maxPrd)
        elif(i<0):
            temp=lowerPrd
            lowerPrd=min(upperPrd*i,i) #向下抽取,如果是i的时候,那么就从新开始玩
            upperPrd=temp*i                         
            maxPrd=max(upperPrd,maxPrd)

   需要梳理的是,这个代码有如下几处是需要更新的。
    1)i<0,也就是当乘以个负数的时候,这个时候积的符号改变,意味着新的uppperPrd和lowerPrd要相互交换了,
    2)i>0的时候,也要进行判断upperPrd=max(upperPrd*i,i),为什么呢? 因为UpperPrd只能说是上限,-2相对于-10也是上限,并不代表上面就一定是正数,因此如果upperPrd为负,那么显然我们要选择i,而不是upperPrd*i作为当前upper连乘积。
   比如 1 2 -3 4这种情况,在2的时候,upperPrd为2,lower为1,在-3的时候逆转了,upper为-3,lower为-6(upper都变负数了);而到4的时候我们就需要max函数进行判断刚才说的了
   upperPrd和lowerPrd在整个的过程中,只保留截止到当前值为止最上限(或最下限)的乘积:它从两种选择中进行筛选,1)乘以当前值后的Product,如果当前值为负值,那么显然是不合算的,他会选择下一种 2)就选择当前值。、


2 如果一段时间内我们的连续积有0出现了,那么我们需要在之前的基础上进行一点修改了。---------------------------------------------
  比如 [1 -2 3 4 0 9 8 ] 
  我们在之前计算了半天的东西到了0的时候,都功亏一魁了。
  怎么办呢?
  这个时候我们只需要遇到0的时候重置一下upperPrd,lowerPrd和maxProduct就行了,后面的步骤继续照着此前讲的计算就行了


整体代码-------------------------------------------------------------------------------------------------------------

class Solution:
    # @param A, a list of integers
    # @return an integer
    def maxProduct(self, A):
        maxPrd=-10000
        upperPrd=1
        lowerPrd=1
        
        #跑的时候记录在当前位置的一个正的和负的连续集cursor,一旦为0,从头算起,
        #是不是最大值这件事全交给maxPrd来记录,正负集子不管
            
        for i in A:
            if(i>0):
                upperPrd=max(upperPrd*i,i) #向上抽取,如果是i的时候,那么就从新开始玩 和下一行不可调换
                lowerPrd=lowerPrd*i            
                maxPrd=max(upperPrd,maxPrd)
            elif(i<0):
                temp=lowerPrd
                lowerPrd=min(upperPrd*i,i) #向下抽取,如果是i的时候,那么就从新开始玩
                upperPrd=temp*i                         
                maxPrd=max(upperPrd,maxPrd)
            else:
                upperPrd=1
                lowerPrd=1    
                maxPrd=max(maxPrd,i)# 遇到输入A=[0]的情况,可以将maxPrd置为0
        return maxPrd
        

你可能感兴趣的:(编程练习思考[3]---leetcode--Maximum Product Subarray)