<算法导论>练习4.1

4.1-1
所有元素都是负数时,最大子数组的和就是A中最大的元素。所有程序会返回A中最大的数。

4.1-2
两个for循环嵌套,且最大迭代次数是n,时间复杂度是 Θ ( n 2 ) \Theta(n^2) Θ(n2)

def find_maximum_subarray(a):
    n=len(a)
    max_sum=-float('inf')
    low=0;high=0
    for i in range(n):
        sum_da=0
        for j in range(i,n):
            sum_da+=a[j]
            if sum_da>max_sum:
                max_sum=sum_da
                low=i
                high=j
    return low,high,max_sum

if __name__ == '__main__':
    a=[13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
    l,h,ma=find_maximum_subarray(a)
    print('最大子数组范围',[l,h])   # python里列表下标从0开始
    print('最大和为:',ma)

4.1-3
在我的笔记本电脑上, n 0 n_0 n0是35.混合的方法交叉点会好一些。

4.1-4
计算完成后,若得出的最大子数组的和小于0,返回空数组即可。

4.1-5
没有按照题目中所说的方法,思想是:如果某一段序列A[i…j]的和求出来是小于0的,那么包含这一段的新序列B[m,…i…j…n]肯定比不包含它要小,如果A在B的端点处,那么B可以直接舍弃A。每个元素操作一次,复杂度为 Θ ( n ) \Theta(n) Θ(n)

def find_maximum_subarray(a):
    n=len(a)
    max_sum=-float('inf')
    sum_a=-float('inf')
    c_high=0;c_low=0
    low=0;high=0
    for j in range(n):
        c_high=j
        if sum_a>0:
            sum_a+=a[j]
        else:
            c_low=j
            sum_a=a[j]
        if sum_a>max_sum:
            max_sum=sum_a
            low=c_low
            high=c_high
    return low,high,max_sum

if __name__ == '__main__':
    a=[13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
    l,h,ma=find_maximum_subarray(a)
    print('最大子数组范围',[l,h])   # python里列表下标从0开始
    print('最大和为:',ma)

有一种更一般的求最大子序和的问题是规定子序的长度不能超过M,对于这个问题上面的做法就不适用了,更通用的方法是“前缀和+单调队列”的方法来做。
前缀和:若已知A[1,2,…n],可以计算出其前缀和S[1,…n],其中:
S [ i ] = A [ 1 ] + A [ 2 ] + . . . + A [ i ] S[i]=A[1]+A[2]+...+A[i] S[i]=A[1]+A[2]+...+A[i]
那么A[i,…j]这一段的子序和就等于S[j]-S[i-1].

单调队列:即队列中存储的序列是单调的,那么在取出其中的最值时只需要O(1)的操作。

def find_maximun_subarray(matrix,m):
    n=len(matrix)
    s = [0 for _ in range(n + 1)]
    q = [0 for _ in range(n + 1)]
    #求前缀和
    for i in range(n):
        s[i + 1] = s[i] + matrix[i]
    # print(s)

    ans = -float('inf')
    l = 0;
    r = 0  # 队列的左右端点
    for i in range(1, n + 1):
        if i - q[l] > m:
            l += 1
        ans = max(ans, s[i] - s[q[l]])
        # print('i=',i,'q=',q,'q[l]=',q[l],'ans=',ans,'q[r]= ',q[r],'l=',l,'r=',r)
        while l <= r and s[q[r]] >= s[i]:
            r -= 1
        r = r + 1
        q[r] = i
    return ans
if __name__ == '__main__':
    m=5   # 最大子序长度,
    a = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
    ans=find_maximun_subarray(a,m)
    print(ans)

其中m是规定的最大子序长度,当 m > = A . l e n g t h m>=A.length m>=A.length时,就是书中例题的样子了。

你可能感兴趣的:(算法导论,算法)