最大子序列和

------------------------------------maxsubsum.go------------------------------------------

package maxsubsum

// 問題描述:最大子序列和
// 給定(有可能爲負的)整數A1A2,...,An,求sum(Ai,...,Aj)最大值(如所有整數均爲負數,則最大子序列和爲0)
// -2,11,-4,13,-5,-2,答案爲20(從A2到A4)

// 暴力枚舉所有情況 時間複雜度 o(n^2) 空間複雜度 o(1)
func maxSubSum1(arr []int) (max int) {
   length := len(arr)
   for i := 0; i < length; i++ {
      tmpMax := 0
      for j := i; j < length; j++ {
         tmpMax += arr[j]
         if tmpMax >= max {
            max = tmpMax
         }
      }
   }
   return
}

// 使用遞歸 將數組中間拆分,最大值可能出現在左半部分,或者右半部分,或者跨越左右兩部分
// 時間複雜度 o(NlogN) 空間複雜度 o(n)
func maxSubSum2(arr []int) (max int) {
   size := len(arr)
   // 遞歸出口,子序列沒有元素或者只剩一個元素時結束遞歸
   if size < 1 {
      return
   }
   if size == 1 {
      if arr[0] > 0 {
         max = arr[0]
      }
      return
   }

   // 遞歸計算左右兩部分的最大值
   center := size / 2
   maxSumLeft := maxSubSum2(arr[0:center])
   maxSumRight := maxSubSum2(arr[center:])

   // 計算可能跨越左右兩部分的最大值
   // 從中間切分點向左,向右分別計算最大值,二者之和爲跨越中點的最大值
   var leftMaxSum, leftTempMaxSum int
   for i := center - 1; i > -1; i-- {
      leftTempMaxSum += arr[i]
      if leftMaxSum <= leftTempMaxSum {
         leftMaxSum = leftTempMaxSum
      }
   }
   var rightMaxSum, rightTempMaxSum int
   for i := center; i < size; i++ {
      rightTempMaxSum += arr[i]
      if rightMaxSum <= rightTempMaxSum {
         rightMaxSum = rightTempMaxSum
      }
   }
   maxSumCenter := leftMaxSum + rightMaxSum

   // 從左最大值,右最大值,中間最大值中選擇最大值爲最終結果
   if maxSumLeft > maxSumRight {
      if maxSumLeft > maxSumCenter {
         return maxSumLeft
      } else {
         return maxSumCenter
      }
   } else {
      if maxSumRight > maxSumCenter {
         return maxSumRight
      } else {
         return maxSumCenter
      }
   }
}

// 優化過的算法
// 從左到右依次掃描求和,如果某值爲負數,其不可能爲序列的起始,繼續判斷下一個值;某個子序列的和<0,則該序列不可能爲最大和子序列的一部分
// 時間複雜度 o(n 空間複雜度 o(1)
func maxSubSum3(arr []int) (max int) {
   var tmpSum int
   for _, val := range arr {
      tmpSum += val
      if tmpSum > max {
         max = tmpSum
      }
      if tmpSum < 0 {
         tmpSum = 0
      }

   }
   return
}

--------------------------------------------maxsubsum_test.go-----------------------------------------------

package maxsubsum

import (
   "testing"
   "math/rand"
   "time"
   "fmt"
)

type Data struct {
   Arr []int
   Max int
}

var data = []Data{
   {[]int{-2, 11, -4, 13, -5, -2}, 20},
   {[]int{4, -3, 5, -2, -1, 2, 6, -2}, 11},
}

func TestMaxSubSum(t *testing.T) {
   for i,f:=range []func([]int)int{maxSubSum1,maxSubSum2,maxSubSum3}{
      for _, item := range data {
         max := f(item.Arr)
         if max != item.Max {
            t.Errorf("method %d input %v expect %d but got %d \n", i,item.Arr, item.Max, max)
         }
      }
   }


}

func TestLargeScale(t *testing.T) {

   // 生成長度爲10萬的測試數組
   rand.Seed(time.Now().UnixNano())
   arr:=make([]int,100000)
   for i:=0;i<len(arr);i++{
      flag :=1
      if rand.Intn(3)==1{
         flag=-1
      }
      arr[i]=rand.Intn(1000)*flag
   }

   for i,f:=range []func([]int)int{maxSubSum1,maxSubSum2,maxSubSum3}{
      start:=time.Now().UnixNano()
      max:=f(arr)
      end:=time.Now().UnixNano()
      fmt.Printf("方式%d 計算結果: %d  耗時:%d\n",i,max,end-start)
   }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章