连续子序列最大和问题---python实现

连续子序列最大和问题—python实现

问题:连续子序列最大和
给定一个数字序列[A1A2A3…An],求i,j(1<=i<=j<=n)使得Ai…Aj和最大,
输出这个最大和(连续大子序列最大和)
例如:
输入:
L=[-2 ,6, -1, 5, 4, -7, 2, 3]
输入:
14 (即6,-1,5,4这个序列的和)

方法一

暴力算法 时间复杂度O(N^3)
即求出每个子序列的和,找到最大的和

def maxsub1(nums):
    maxsub = nums[0]
    for i in range(len(nums)):#i为子序列起始位置
        j = i
        for j in range(len(nums)):#j为子序列的结束位置
            s = 0
            k = j
            for k in range(i,j+1):#遍历子序列求和
                s += nums[k]
            if s > maxsub:
                maxsub = s
    return maxsub

方法二

简单优化 时间复杂度O(N^2)
按照上面的算法,计算子序列[Ai…A[j]]的和,我们需要遍历
子序列的每个元素,其实我们在计算[Ai…A[j]的和之前,已经
计算了[Ai…A[j-1]]的和,因此只需计算sum(A[i]…A[j-1]]+A[j]
即可得到子序列[Ai…A[j]]的和

def maxsub2(nums):
    maxsub = nums[0]
    for i in range(len(nums)):#i为子序列起始位置
        j = i
        s = nums[i]
        for j in range(len(nums)):#j为子序列的结束位置
            s += nums[k]
            if s > maxsub:
                maxsub = s
    return maxsub

方法三

分治算法 时间复杂度O(NlogN)
将序列平均分为左右两个子序列,存在下面三种情况:
1.要求的连续子序列在左序列中
2.要求的连续子序列在右序列中
3.要求的连续子序列刚好横跨分割点,即左右序列各占一部分
对于第1、2种情况:分别利用递归求出连续子序列的最大和S1、S2,
对于第3情况:最大子序列和由左序列最大和(包含左序列最后一个元素)
右序列最大和(包含右序列第一个元素)构成,
将两个和相加得到S3
那么要求的最大子序列和为这三个数S1,S2,S3的最大者
例如:
左序列 | 右序列
4 -3 5 -2 | -1 2 6 -2
左序列最大子序列和为6(A1到A3)
右序列最大子序列和为8(A6到A7)
横跨分割点的最大子序列的和为11:
即左序列包含最后一个元素最大和4(A1到A4),右序列包含第一个元素最大和7(A5到A7)
4+7=11

方法四

动态规划 时间复杂度O(N)
分析
步骤1:
令dp[i]表示已A[i]作为结尾的连续子序列的最大和
步骤2:
因为dp[i]要求必须以A[i]结尾的连续序列,那么只有两种情况:
1.这个最大连续序列只有一个元素,即以A[i]开始,以A[i]结尾
2.这个最大和的连续序列有多个元素,即以A[p]开始(p小于i),以A[i]结尾
对于情况1,最大和就是A[i]本身
对于情况2,最大和是da[i-1]+A[i]
于是得到状态转移方程:
dp[i]=max{A[i],dp[i-1]+A[i]}
步骤3:
连续子序列的和为
maxsub[n]=max{dp[i]} (1<=i<=n)

def maxsum4(nums):
    if len(nums) == 1:
        return nums[0]
    dp = res = nums[0]

    for i in range(1,len(nums)):
        dp = max(nums[i],dp + nums[i])
        res = max(dp,res)
    return res

下边是测试代码

from random import randrange
import time

#方法一
def maxsum1(nums):
    maxsum = nums[0]
    print(len(nums))
    for i in range(len(nums)):#i为子序列起始位置
        j = i
        for j in range(i,len(nums)):#j为子序列的结束位置
            s = 0
            k = j
            for k in range(i,j+1):#遍历子序列求和
                s += nums[k]
            if s > maxsum:
                maxsum = s
    return maxsum

#方法二
def maxsum2(nums):
    maxsum = nums[0]
    #print(len(nums))
    for i in range(len(nums)):#i为子序列起始位置
        j = i
        s = 0
        for j in range(i,len(nums)):#j为子序列的结束位置
            s += nums[j]
            #print(s)
            if s > maxsum:
                maxsum = s
    return maxsum

#方法三   
def maxsum3(nums):
    if len(nums) == 1:
        return nums[0]
    #分组
    center = len(nums)//2
    left_nums = nums[0:center]
    right_nums = nums[center:len(nums)]

    #分别求左右序列最大子序列和
    left_maxsum = maxsum3(left_nums)
    right_maxsum = maxsum3(right_nums)

    #求左序列最大和(包括最后一个元素)
    left_sum = 0
    left_max= left_nums[len(left_nums)-1]
    i = len(left_nums)-1
    while i >= 0:
        left_sum += left_nums[i]

        if left_sum > left_max:
            left_max = left_sum
        i -= 1

    #求右序列最大和(包括第一个元素)
    right_sum =0 
    right_max = right_nums[0]
    i = 0
    while i < len(right_nums):
        right_sum += right_nums[i]
        if right_sum > right_max:
            right_max = right_sum
        i += 1

    l = [left_maxsum,right_maxsum,left_max + right_max]
    return max(l)

#方法四
def maxsum4(nums):
    if len(nums) == 1:
        return nums[0]
    dp = res = nums[0]

    for i in range(1,len(nums)):
        dp = max(nums[i],dp + nums[i])
        res = max(dp,res)
    return res 

#产生从start到stop的lenth个数组成的队列
def make_list(start,stop,lenth):
    nums = []
    while lenth:
        nums.append(randrange(start,stop,1))
        lenth -= 1
    return nums

nums = make_list(-10,10,1000)        
#L = [-2,6,-1,5,4,-7,2,3]
#print("数组序列:",nums)
s1 = time.time()
value = maxsum1(nums)
s2 = time.time()
print("方法一:",s2-s1)
print("最大连续子序列和:",value)

s1 = time.time()
value = maxsum2(nums)
s2 = time.time()
print("方法二:",s2-s1)
print("最大连续子序列和:",value)

s1 = time.time()
value = maxsum3(nums)
s2 = time.time()
print("方法三:",s2-s1)
print("最大连续子序列和:",value)

s1 = time.time()
value = maxsum4(nums)
s2 = time.time()
print("方法四:",s2-s1)
print("最大连续子序列和:",value)

猜你喜欢

转载自blog.csdn.net/yangfengyougu/article/details/81807950