求解数组最大子数组和最大问题

版权声明:本文为博主原创文章,欢迎评论 https://blog.csdn.net/wh_585/article/details/82155010

暴力递归方法

def maxChildArray(arr):
    lenArr = len(arr)
    maxLocation = [[-9999999999999, 0, 0]]                #数据由3个子项构成,最大值,起点,长度
    for i in range(lenArr):                               #取数据-第i轮 第i轮取i + 1个数据
        for j in range(lenArr):                           #从哪个位置开始取数据
            tmp = 0
            if j + i <= lenArr - 1:                       #判断索引是否越界
                for k in range(j, j + i + 1):             #range(j, j + i + 1)从第j个开始取数据,额外可以取i个, j + i + 1取不到
                    tmp += arr[k]                         #求和未使用sum()函数,是因为不想对原数组进行切片操作,需占用额外空间
                if tmp > maxLocation[0][0]:
                    maxLocation.clear()
                    maxLocation.append([tmp, j, i + 1])
                elif tmp == maxLocation[0][0]:
                    maxLocation.append([tmp, j, i + 1])
    return maxLocation

上述方法可以若数组中存在多组解,则会返回包含所有解的列表,这种方法的弊端在于空间复杂度过高O(n**3)


分治法 + 递归求解思路

"""
分治法:
    left:左边最大值
    right:右边最大值
    post + pre: 最大后缀 + 最大前缀
    最大值: max(left, right, post + pre)
"""
import math

def maxArraySub(arr, from_, to):
    print('from: {}, to: {}'.format(from_, to))
    if from_ == to:
        return arr[to]
    mid = math.floor((from_ + to)/2)
    left = maxArraySub(arr, from_, mid)
    right = maxArraySub(arr, mid + 1, to)

    postLeft = now = arr[mid]
    for i in range(mid - 1, from_ - 1, -1):
        now += arr[i]
        postLeft = max(now, postLeft)

    preRight = now = arr[mid + 1]
    for i in range(mid + 2, to + 1):
        now += arr[i]
        preRight = max(now, preRight)

    print(left, right, postLeft, preRight)
    return max(left, right, postLeft + preRight)

该方法将时间复杂度降至O(nlogn),已经算是很有进步,但是对于此题优化方式还未完事,请继续观看


动态规划

"""
DP求解最大子数组和问题
该问题可以理解为,某一项的最大前缀值为整个数组的子数组求和中最大的
存在:a[i] 使得 a[n] + ... + a[i] >= sum(sub(arr)p)(
    即:从arr的子数组中任取一项的值均小于或等于以i为结尾的数组的最大前缀的值)
"""
def maxChildArrDP(arr):
    dp = [arr[0]]                           #此处使用数组仍然具有可以优化的空间
    for i in range(1, len(arr)):
        if dp[i - 1] + arr[i] >= arr[i]:
            dp.append(dp[i - 1] + arr[i])
        else:
            dp.append(arr[i])
    return max(dp)

#通过使用pre记录前一项的最大前缀和,和当前变量作比较,滚动记录前一项最大前缀和,无需开辟n长空间
#优化空间
#opti stands for optimization 优化
def maxChildArrDPOpti(arr):
    pre = arr[0]            #记录前一个最大前缀
    sum = arr[0]            #记录最终结果

    for i in range(1, len(arr)):
        if pre + arr[i] >= arr[i]:
            pre = arr[i] + pre
        else:
            pre = arr[i]
        sum  = pre if pre >= sum else sum
    return sum

一般越是精简的代码,在代码中蕴含的东西越多,每一步的优化过程都是从之前的问题中发现新的问题,在此基础上进行改进,通过使用动态规划方法,将时间复杂度由O(nlogn)优化到O(n),空间复杂度O(1),至此最大子数组和最大的问题求解完成,整个优化过程如上所述,如果哪里有问题欢迎留言探讨。

猜你喜欢

转载自blog.csdn.net/wh_585/article/details/82155010
今日推荐