问题1,最大子数组
给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。
样例
给出数组[−2,2,−3,4,−1,2,1,−5,3],符合要求的子数组为[4,−1,2,1],其最大和为6
挑战
要求时间复杂度为O(n)
def max_sub(nums):
current_sum=0
total_sum=num[0]
for num in nums:
current_sum=max(current_sum+num,num)
total_sum=max(current_sum,total_sum)
return total_sum
思路:
用current_sum保存好每一步的和,如果current_sum是正数,就会保留之前的current_sum,如果是负数,会从下一个num重新计数。
用total_sum和current_sum的区别是,total_sum决定是否加入当前的新元素,而current_sum决定是否保存之前的元素和。
问题2 最小子数组
给定一个整数数组,找到一个具有最小和的子数组。返回其最小和。
样例
给出数组[1, -1, -2, 1],返回 -3
def minSubArray(nums):
# write your code here
current=0
total=nums[0]
for num in nums:
current=min(current+num,num)
total=min(current,total)
print(total)
return total
思路:
跟求最大子数组的思路是一样的。
问题3,最大子数组 II
给定一个整数数组,找出两个 不重叠 子数组使得它们的和最大。
每个子数组的数字在数组中的位置应该是连续的。
返回最大的和。
样例
给出数组 [1, 3, -1, 2, -1, 2]
这两个子数组分别为 [1, 3] 和 [2, -1, 2] 或者 [1, 3, -1, 2] 和 [2],它们的最大和都是 7
挑战
要求时间复杂度为 O(n)
def maxTwoSubArrays(nums):
# write your code here
n=len(nums)
total_left=nums[0]
current_left=0
left_sum_array=[0]*n
for i in range(n):
current_left=max(current_left+nums[i],nums[i])
total_left=max(current_left,total_left)
left_sum_array[i]=total_left
# print('left',total_left)
total_right=nums[n-1]
current_right=0
right_sum_array=[0]*n
for i in range(n-1,-1,-1):
current_right=max(current_right+nums[i],nums[i])
total_right=max(current_right,total_right)
right_sum_array[i]=total_right
# print('right',total_right)
final_sum=-100000
for i in range(n-1):
final_sum=max(final_sum,right_sum_array[i+1]+left_sum_array[i])
# (0)>>>(i) | (i+1)<<<(n-1)
# print(final_sum)
return final_sum
思路:
题目要求是两个不重叠子数组的和最大
我用一个left数组表达从第0个元素到第i个元素中,随i变化的最大数组和,这就是之前问题1的解法;同理,用一个right数组表达从右往左第n-1个元素到第i个元素,随i变化的最大数组和。
然后以i为分界线,使得i取0~n-1,来找两个子数组最大的和,过程是这样的
(0)>>>(i) | (i+1)<<<(n-1)
问题4 最大子数组差
给定一个整数数组,找出两个不重叠的子数组A和B,使两个子数组和的差的绝对值|SUM(A) - SUM(B)|最大。
返回这个最大的差值。
样例
给出数组[1, 2, -3, 1],返回 6
挑战
时间复杂度为O(n),空间复杂度为O(n)
class Solution:
"""
@param nums: A list of integers
@return: An integer indicate the value of maximum difference between two substrings
"""
def maxDiffSubArrays(self, nums):
# write your code here
n=len(nums)
current_left_max,current_left_min=0,0
total_left_max,total_left_min=nums[0],nums[0]
save_left_max,save_left_min=[0]*n,[0]*n
for i in range(n):
current_left_max=max(current_left_max+nums[i],nums[i])
total_left_max=max(current_left_max,total_left_max)
save_left_max[i]=total_left_max
# print('total_left_max',total_left_max)
current_left_min=min(current_left_min+nums[i],nums[i])
total_left_min=min(current_left_min,total_left_min)
save_left_min[i]=total_left_min
# print('total_left_min',total_left_min)
current_right_min,current_right_max=0,0
total_right_min,total_right_max=nums[n-1],nums[n-1]
save_right_min,save_right_max=[0]*n,[0]*n
for i in range(n-1,-1,-1):
current_right_max=max(current_right_max+nums[i],nums[i])
total_right_max=max(total_right_max,current_right_max)
save_right_max[i]=total_right_max
# print('total_right_max',total_right_max)
current_right_min=min(current_right_min+nums[i],nums[i])
total_right_min=min(total_right_min,current_right_min)
save_right_min[i]=total_right_min
# print('total_right_min',total_right_min)
final_diff=-100000
for i in range(n-1):
final_diff=max(final_diff,abs(save_right_max[i+1]-save_left_min[i]),abs(save_left_max[i]-save_right_min[i+1]))
# print(final_diff)
return final_diff
思路,如果已经刷过了之前的几道题,那么这题就很简单了,找到四个数组,分别是,左到右最大子数组,左到右最小子数组;右到左最大子数组,右到左最小子数组。将他们大减小来来比较,进而找到最大子数组差。
下个博客讲best time to buy and sell stocks,和这个问题是一类问题。