国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

動態規劃法(八)最大子數組問題(maximum subarray problem)

jzman / 606人閱讀

摘要:動態規劃法用表示最大子數組的結束下標為的情形,則對于,有這樣就有了一個子結構,對于初始情形,遍歷就能得到這個數組,其最大者即可最大子數組的和。動態規劃法想法巧妙,運行效率也高,但是沒有普遍的適用性。

問題簡介

??本文將介紹計算機算法中的經典問題——最大子數組問題(maximum subarray problem)。所謂的最大子數組問題,指的是:給定一個數組A,尋找A的和最大的非空連續子數組。比如,數組 A = [-2, -3, 4, -1, -2, 1, 5, -3], 最大子數組應為[4, -1, -2, 1, 5],其和為7。
??首先,如果A中的元素全部為正(或非負數),則最大子數組就是它本身;如果A中的元素全部為負,則最大子數組就是第一個元素組成的數組。以上兩種情形是平凡的,那么,如果A中的元素既有正數,又有負數,則該如何求解呢?本文將介紹該問題的四種算法,并給出后面三種算法的Python語言實現,解決該問題的算法如下:

暴力求解

分治法

Kadane算法

動態規劃法

??下面就這四種算法做詳細介紹。

暴力求解

??假設數組的長度為n,暴力求解方法的思路是很簡單的,就是將子數組的開始坐標和結束坐標都遍歷一下,這樣共有$C_{n}^{2}$中組合方式,再考慮這所有組合方式中和最大的情形即可。
??該算法的運行時間為$O(n^{2})$,效率是很低的。那么,還有其它高效的算法嗎?

分治法

??分治法的基本思想是將問題劃分為一些子問題,子問題的形式與原問題一樣,只是規模更小,遞歸地求解出子問題,如果子問題的規模足夠小,則停止遞歸,直接求解,最后將子問題的解組合成原問題的解。
??對于最大子數組,我們要尋求子數組A[low...high]的最大子數組。令mid為該子數組的中央位置,我們考慮求解兩個子數組A[low...mid]和A[mid+1...high]。A[low...high]的任何連續子數組A[i...j]所處的位置必然是以下三種情況之一:

完全位于子數組A[low...mid]中,因此$lowleq ileq j leq mid.$

完全位于子數組A[mid+1...high]中,因此$mid< ileq j leq high.$

跨越了中點,因此$low leq i leq mid < j leq high.$

因此,最大子數組必定為上述3種情況中的最大者。對于情形1和情形2,可以遞歸地求解,剩下的就是尋找跨越中點的最大子數組。
??任何跨越中點的子數組都是由兩個子數組A[i...mid]和A[mid+1...j]組成,其中$low leq i leq mid$且$mid

FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high):
left-sum = -inf
sum = 0
for i = mid downto low
    sum = sum + A[i]
    if sum > left-sum
        left-sum = sum
        max-left = i
        
right-sum = -inf
sum = 0
for j = mid+1 to high
    sum = sum + A[j]
    if sum > right-sum
        right-sum = sum
        max-right = i
        
return (max-left, max-right, left-sum+right+sum)

??有了FIND-MAX-CROSSING-SUBARRAY我們可以找到跨越中點的最大子數組,于是,我們也可以設計求解最大子數組問題的分治算法了,其偽代碼如下:

FIND-MAXMIMUM-SUBARRAY(A, low, high):
if high = low
    return (low, high, A[low])
else 
    mid = floor((low+high)/2)
    (left-low, left-high, left-sum) = FIND-MAXMIMUM-SUBARRAY(A, low, mid)
    (right-low, right-high, right-sum) = FIND-MAXMIMUM-SUBARRAY(A, mid+1, high)
    (cross-low, cross-high, cross-sum) = FIND-MAXMIMUM-SUBARRAY(A, low, mid, high)
    
    if left-sum >= right-sum >= cross-sum
        return (left-low, left-high, left-sum)
    else right-sum >= left-sum >= cross-sum
        return (right-low, right-high, right-sum)
    else
        return (cross-low, cross-high, cross-sum)

??顯然這樣的分治算法對于初學者來說,有點難度,但是熟能生巧, 多學多練也就不難了。該分治算法的運行時間為$O(n*logn).$

Kadane算法

??Kadane算法的偽代碼如下:

Initialize:
    max_so_far = 0
    max_ending_here = 0

Loop for each element of the array
  (a) max_ending_here = max_ending_here + a[i]
  (b) if(max_ending_here < 0)
            max_ending_here = 0
  (c) if(max_so_far < max_ending_here)
            max_so_far = max_ending_here
return max_so_far

??Kadane算法的簡單想法就是尋找所有連續的正的子數組(max_ending_here就是用來干這事的),同時,記錄所有這些連續的正的子數組中的和最大的連續數組。每一次我們得到一個正數,就將它與max_so_far比較,如果它的值比max_so_far大,則更新max_so_far的值。

動態規劃法

?? 用MS[i]表示最大子數組的結束下標為i的情形,則對于i-1,有:
$$MS[i] = max{MS[i-1], A[i]}.$$
這樣就有了一個子結構,對于初始情形,$MS[1]=A[1].$遍歷i, 就能得到MS這個數組,其最大者即可最大子數組的和。

總結

?? 可以看到以上四種算法,每種都有各自的優缺點。對于暴力求解方法,想法最簡單,但是算法效率不高。Kanade算法簡單高效,但是不易想到。分治算法運行效率高,但其分支過程的設計較為麻煩。動態規劃法想法巧妙,運行效率也高,但是沒有普遍的適用性。

Python程序

?? 下面將給出分治算法,Kanade算法和動態規劃法來求解最大子數組問題的Python程序, 代碼如下:

# -*- coding: utf-8 -*-
__author__ = "Jclian"

import math

# find max crossing subarray in linear time
def find_max_crossing_subarray(A, low, mid, high):
    max_left, max_right = -1, -1

    # left part of the subarray
    left_sum = float("-Inf")
    sum = 0
    for i in range(mid, low - 1, -1):
        sum += A[i]
        if (sum > left_sum):
            left_sum = sum
            max_left = i

    # right part of the subarray
    right_sum = float("-Inf")
    sum = 0
    for j in range(mid + 1, high + 1):
        sum += A[j]
        if (sum > right_sum):
            right_sum = sum
            max_right = j

    return max_left, max_right, left_sum + right_sum

# using divide and conquer to solve maximum subarray problem
# time complexity: n*logn
def find_maximum_subarray(A, low, high):
    if (high == low):
        return low, high, A[low]
    else:
        mid = math.floor((low + high) / 2)
        left_low, left_high, left_sum = find_maximum_subarray(A, low, mid)
        right_low, right_high, right_sum = find_maximum_subarray(A, mid + 1, high)
        cross_low, cross_high, cross_sum = find_max_crossing_subarray(A, low, mid, high)
        if (left_sum >= right_sum and left_sum >= cross_sum):
            return left_low, left_high, left_sum
        elif (right_sum >= left_sum and right_sum >= cross_sum):
            return right_low, right_high, right_sum
        else:
            return cross_low, cross_high, cross_sum

# Python program to find maximum contiguous subarray
# Kadane’s Algorithm
def maxSubArraySum(a, size):
    max_so_far = float("-inf")
    max_ending_here = 0

    for i in range(size):
        max_ending_here = max_ending_here + a[i]
        if (max_so_far < max_ending_here):
            max_so_far = max_ending_here

        if max_ending_here < 0:
            max_ending_here = 0

    return max_so_far

# using dynamic programming to slove maximum subarray problem
def DP_maximum_subarray(arr):
    t = len(arr)
    MS = [0]*t
    MS[0] = arr[0]

    for i in range(1, t):
        MS[i] = max(MS[i-1]+arr[i], arr[i])

    return MS

def main():
    # example of array A
    A = [13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
    # A = [-2, 2, -3, 4, -1, 2, 1, -5, 3]
    # A = [0,-2, 3, 5, -1, 2]
    # A = [-9, -2, -3, -5, -3]
    # A = [1, 2, 3, 4, 5]
    # A = [-2, -3, 4, -1, -2, 1, 5, -3]

    print("using divide and conquer...")
    print("Maximum contiguous sum is",find_maximum_subarray(A, 0, len(A) - 1), "
")

    print("using Kanade Algorithm...")
    print("Maximum contiguous sum is", maxSubArraySum(A, len(A)), "
")

    print("using dynamic programming...")
    MS = DP_maximum_subarray(A)
    print("Maximum contiguous sum is", max(MS), "
")

main()

輸出結果如下:

using divide and conquer...
Maximum contiguous sum is (7, 10, 43) 

using Kanade Algorithm...
Maximum contiguous sum is 43 

using dynamic programming...
Maximum contiguous sum is 43 
參考文獻

算法導論(第三版) 機械工業出版社

https://www.geeksforgeeks.org...

https://algorithms.tutorialho...

注意:本人現已開通兩個微信公眾號: 用Python做數學(微信號為:python_math)以及輕松學會Python爬蟲(微信號為:easy_web_scrape), 歡迎大家關注哦~~

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41824.html

相關文章

  • [Leetcode] Maximum Subarray 序列最大

    摘要:最新更新請見原題鏈接動態規劃復雜度時間空間思路這是一道非常典型的動態規劃題,為了求整個字符串最大的子序列和,我們將先求較小的字符串的最大子序列和。而最大子序列和的算法和上個解法還是一樣的。 Maximum Subarray 最新更新請見:https://yanjia.me/zh/2019/02/... Find the contiguous subarray within an ar...

    summerpxy 評論0 收藏0
  • leetcode152 Maximum Product Subarray

    摘要:題目要求從一個整數數組中找到一個子數組,該子數組中的所有元素的乘積最大。比如數組的最大乘積子數組為思路與代碼這題目考察了動態編程的思想。至于為什么還要比較,是因為如果是一個負數的,那么之前的最小乘積在這里可能就成為了最大的乘積了。 題目要求 Find the contiguous subarray within an array (containing at least one num...

    Arno 評論0 收藏0
  • leetcode53 Maximum Subarray 最大連續數組

    摘要:我們可以分別得出這三種情況下的最大子數列和,并比較得出最大的那個。我們只需要考慮左子列的最大和以及跨越了左右的中子列的最大值。 題目要求 Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given ...

    Bamboy 評論0 收藏0
  • leetcode_53 Maximum Subarray

    摘要:如果單開元素加和更大判斷前面的子數組和是不是小于。此元素就成為了子數組的第一個元素。每次操作都要判斷,當前是否是最大值,更新值。 題目詳情 Find the contiguous subarray within an array (containing at least one number) which has the largest sum.For example, given t...

    y1chuan 評論0 收藏0
  • leetcode-152-Maximum Product Subarray

    摘要:問題本質本質動態規劃問題。局部最優,全局最優。乘法問題,存在的情況是負數或者正數,或者從當前數開始新的連續元素相乘可能發生的情況在某個節點,繼續之前的增大減小,從此節點轉折。所以只要在局部動態中,保持最大最小當前,進行判斷保留即可。 Given an integer array nums, find the contiguous subarray within an array (co...

    thursday 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<