最大子序列和

5 篇文章 0 订阅

------------------------------------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)
   }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值