【每日算法】动态规划五

918.环形子数组的最大和

难度[中等]

给定一个由整数数组 A 表示的环形数组 C,求 C 的非空子数组的最大可能和。

在此处,环形数组意味着数组的末端将会与开头相连呈环状。(形式上,当0 <= i < A.length 时 C[i] = A[i],且当 i >= 0 时 C[i+A.length] = C[i])

此外,子数组最多只能包含固定缓冲区 A 中的每个元素一次。(形式上,对于子数组 C[i], C[i+1], ..., C[j],不存在 i <= k1, k2 <= j 其中 k1 % A.length = k2 % A.length)

 

示例 1:

输入:[1,-2,3,-2]
输出:3
解释:从子数组 [3] 得到最大和 3
示例 2:

输入:[5,-3,5]
输出:10
解释:从子数组 [5,5] 得到最大和 5 + 5 = 10
示例 3:

输入:[3,-1,2,-1]
输出:4
解释:从子数组 [2,-1,3] 得到最大和 2 + (-1) + 3 = 4
示例 4:

输入:[3,-2,2,-3]
输出:3
解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3
示例 5:

输入:[-2,-3,-1]
输出:-1
解释:从子数组 [-1] 得到最大和 -1

分两种情况:

  1. 无环的情况
    此时和数组最大子序列和的解法一样。
  2. 有环的情况
    要使首尾两个子区间的和尽可能的大,则中间的子区间的和应该尽可能的小,然后用数组的总和减去最小子序列和既是首尾两个子区间的最大值。

然后最两种情况的最大值。其中有个特殊的情况,当最大子序列的和为负数时,则说明数组中全部都是负数,则最大的负数就是要找的那个结果。

当数组中都是负数时,最小的子序列和就是数组的全部和,在第2种情况时的结果是0,在和第1种情况取最大值时的结果仍然是0,显然不是要找的结果,因此,在找最大的子序列时,如果是负数,则可以直接返回。

class Solution(object):
    def maxSubarraySumCircular(self, nums):
        
        #假如最大的值不在环中
        n=len(nums)
        max_dp=[0]*n
        min_dp=[0]*n
        max_dp[0]=nums[0]#第一个是
        min_dp[0]=nums[0]#第一个是
        max_num=nums[0]#第一个最大
        min_num=nums[0]#第一个最小
        for i in range(1,n):
            #计算最大的
            max_dp[i]=nums[i]+max(0,max_dp[i-1])
            max_num=max(max_dp[i],max_num)
            #计算最小的
            min_dp[i]=nums[i]+min(0,min_dp[i-1])
            min_num=min(min_dp[i],min_num)

        # print(total)
        # print(max_num,max_dp)#最大值
        # print(min_num,min_dp)#最小的
        if max_num<0:
            return max_num
        total=sum(nums)#数组中的所有数之和
        return max(max_num,total-min_num)

152.乘积最大子数组

难度[中等]

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
class Solution(object):
    def maxProduct(self, nums):
        #因为正数乘以负数,变成小值 ;负数乘以负数,变成大值
        #所以每每次在计算一个最大值时,还需要一个小值与当前数值进行相乘,最最大的那个作为当前的最大值
        n=len(nums)
        if n<2:
            return nums[0]
        max_dp,min_dp=[0]*n,[0]*n
        max_dp[0],min_dp[0]=nums[0],nums[0]
        res=nums[0]
        for i in range(1,n):
            max_dp[i]=max(max_dp[i-1]*nums[i],min_dp[i-1]*nums[i],nums[i])
            min_dp[i]=min(max_dp[i-1]*nums[i],min_dp[i-1]*nums[i],nums[i])
            res=max(res,max_dp[i])
        return res

1567.乘积为正数的最长子数组长度

难度[中等]

给你一个整数数组 nums ,请你求出乘积为正数的最长子数组的长度。
一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。
请你返回乘积为正数的最长子数组长度。

示例  1:

输入:nums = [1,-2,-3,4]
输出:4
解释:数组本身乘积就是正数,值为 24 。

示例 2:

输入:nums = [0,1,-2,-3,-4]
输出:3
解释:最长乘积为正数的子数组为 [1,-2,-3] ,乘积为 6 。
注意,我们不能把 0 也包括到子数组中,因为这样乘积为 0 ,不是正数。
示例 3:

输入:nums = [-1,-2,-3,0,1]
输出:2
解释:乘积为正数的最长子数组是 [-1,-2] 或者 [-2,-3] 。
示例 4:

输入:nums = [-1,2]
输出:1
示例 5:

输入:nums = [1,2,3,5,-6,4,0,10]
输出:4
if f(x-1)>0 and nums[i]>0:#这个没问题
    f(x)=f(x-1)+1
if f(x-1)>0 and nums[i]<0:
    f(x)=1
if f(x-1)<0 and nums[i]>0:
    f(x)=1
if f(x-1)<0 and nums[i]<0:#这个也没问题
    f(x)=f(x-1)+1
posted @ 2021-09-08 15:00  Hitechr  阅读(32)  评论(0编辑  收藏  举报