最大子數(shù)組問題的幾種解法

分治算法

最近看到《算法導論》的分治策略一節(jié)竹宋,看到的一個題目可以優(yōu)化引申出來多種解法石蔗,同時也可以幫助理解分治策略的化整為零和動態(tài)規(guī)劃的動態(tài)轉移方程的思維杰赛。

最大子數(shù)組問題

最大子數(shù)組:數(shù)組 A 中的和最大的非空連續(xù)子數(shù)組顽腾。

暴力解法 O(n^2)

這個問題可以用暴力解法蓄髓,兩層循環(huán)遍歷汪茧,時間復雜度為 O(n^2)裂垦,當然最容易想到的并不是最好的解法葡秒。

package main

import (
    "fmt"
)

func main() {
    A := []int{13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7}
    left, right, sum := FindMaxSubArray(A)
    fmt.Println(left, right, sum)
}

func FindMaxSubArray(A []int) (left, right, sum int){
    // 這里先不考慮 max 取值的問題魔招,可以取切片的第一個元素或者 int 的最小值晰搀。
    var max int
    for i := 0; i < len(A); i++ {
        sum = 0
        for j := i; j < len(A); j++ {
            sum += A[j]
            if sum > max {
                max = sum
                left, right = i, j
            }
        }
    }
    return left, right, sum
}

可以得知最大的和為 43,即下標 7, 10 之間的子數(shù)組办斑。

分治解法 O(nlgn)

既然這一節(jié)是講分治策略外恕,那么怎么用分治的思想來優(yōu)化呢。這個解法確實比較難懂乡翅,如果讓腦袋去跑一遍遞歸鳞疲,真的有點累。那么分治本來就是一種局部整體的思想蠕蚜,我們把切片分成三組尚洽,左,中靶累,右腺毫。那么我們只需要得出,這三個子集的最大值即可挣柬。然后再不斷分化下去潮酒,最后把最大值冒上來。分治解法的關鍵就是如何用整體局部的思想把問題抽象化邪蛔。

image.png
func FindMaxCrossingSubArray(A []int, low, mid, high int) (int, int, int){
    // 這個函數(shù)為什么從中間分開算呢急黎?因為得出的結果必須要跟 mid 位相關
    var maxLeft, maxRight int
    // 取負無窮大就行,這里簡化處理
    leftSum := -99999
    sum := 0
    for i := mid; i >= low; i-- {
        sum += A[i]
        if sum > leftSum {
            leftSum = sum
            maxLeft = i
        }
    }
    rightSum := -99999
    sum = 0
    for j := mid + 1; j <= high; j++ {
        sum += A[j]
        if sum > rightSum {
            rightSum = sum
            maxRight = j
        }
    }
    return maxLeft, maxRight, leftSum+rightSum
}

func FindMaxSubArray(A []int, low, high int) (int, int, int) {
    if low == high {
        return low, high, A[low]
    } else {
        mid := (low + high) >> 1
        // 求左半?yún)^(qū)子數(shù)組最大值
        leftLow, leftHigh, leftSum := FindMaxSubArray(A, low, mid)
        // 求右半?yún)^(qū)子數(shù)組最大值
        rightLow, rightHigh, rightSum := FindMaxSubArray(A, mid+1, high)
        // 求包含中位數(shù)區(qū)子數(shù)組的最大值
        crossLow, crossHigh, crossSum := FindMaxCrossingSubArray(A, low, mid, high)
        if leftSum >= rightSum  && leftSum >= crossSum {
            return leftLow, leftHigh, leftSum
        } else if rightSum >= leftSum && rightSum >= crossSum {
            return rightLow, rightHigh, rightSum
        } else {
            return crossLow, crossHigh, crossSum
        }
    }
}

可以將時間復雜度降低到 O(n) 嗎? 動態(tài)規(guī)劃叁熔。

線性解法 O(n)

從題目上看委乌,可以發(fā)現(xiàn)這道題滿足動態(tài)規(guī)劃的思想∪倩兀可以求得動態(tài)轉移方程為:F(n) = max(F(n-1)+A[n], A[n])

func FindMaxSubArray(nums []int) (left, right, maxNum int) {
    var isLeftMax bool
    maxNum = nums[0]
    v := make([]int, len(nums))
    v[0] = nums[0]
    for i := 1; i < len(nums); i++ {
        v[i], isLeftMax = max(nums[i], v[i-1] + nums[i])
        if isLeftMax {
            left = i
        }
        if v[i] > maxNum {
            maxNum = v[i]
            right = i
        }
    }
    return left, right, maxNum
}

func max(a, b int) (int, bool) {
    if a > b {
        return a, true
    }
    return b, false
}

題目

53 最大子序和

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遭贸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子心软,更是在濱河造成了極大的恐慌壕吹,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件删铃,死亡現(xiàn)場離奇詭異耳贬,居然都是意外死亡,警方通過查閱死者的電腦和手機猎唁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門咒劲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诫隅,你說我怎么就攤上這事腐魂。” “怎么了逐纬?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵蛔屹,是天一觀的道長。 經(jīng)常有香客問我豁生,道長兔毒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任甸箱,我火速辦了婚禮育叁,結果婚禮上,老公的妹妹穿的比我還像新娘芍殖。我一直安慰自己擂红,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布围小。 她就那樣靜靜地躺著,像睡著了一般树碱。 火紅的嫁衣襯著肌膚如雪肯适。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天成榜,我揣著相機與錄音框舔,去河邊找鬼。 笑死,一個胖子當著我的面吹牛刘绣,可吹牛的內(nèi)容都是我干的樱溉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纬凤,長吁一口氣:“原來是場噩夢啊……” “哼福贞!你這毒婦竟也來了?” 一聲冷哼從身側響起停士,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挖帘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后恋技,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拇舀,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年蜻底,在試婚紗的時候發(fā)現(xiàn)自己被綠了骄崩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡薄辅,死狀恐怖要拂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情长搀,我是刑警寧澤宇弛,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站源请,受9級特大地震影響枪芒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谁尸,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一舅踪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧良蛮,春花似錦抽碌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至皮胡,卻和暖如春痴颊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背屡贺。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工蠢棱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锌杀,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓泻仙,卻偏偏與公主長得像糕再,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子玉转,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容