求数组连续最大和(暴力求解和动态规划)

1. 问题

一个有 n 个元素的数组,这 n 个元素既可以是正数也可以是负数,数组中连续的一个或者多个元素可以组成一个连续的子数组,一个数组可能有多个连续的子数组,求子数组的最大值。如数组 [1, -2, 4, 8, -4, 7, -1, -5] 其最大和的子数组为 [4, 8 -4, 7],最大值为 15。

2. 思路实现

2.1 暴力法

依次遍历生成所有子数组,并求出子数组的和,然后取最大值就是题目要求。

package main

import (
	"fmt"
	"math"
)

func getMax(a []int) int {
	max := math.MinInt64
	for i := 0; i < len(a); i++ {
		sum := a[i]
		for j := i + 1; j < len(a); j++ {
			sum += a[j]
			if sum > max {
				max = sum
			}
		}
	}
	return max
}

func main() {
	arr := []int{1, -2, 4, 8, -4, 7, -1, -5}
	fmt.Println(getMax(arr))
}

2.2 动态规划思想

首先可以根据数组最后一个元素 a[n-1] 与最大子数组的关系可以分为以下 3 种情况:

  1. 最大子数组包含 a[n-1] ,即最大子数组以 a[n-1] 结尾
  2. a[n-1] 单独构成最大子数组
  3. 最大子数组不包含 a[n-1],那么求 a[1…n-1] 的最大子数组可以转换为求 a[1…n-2] 的最大子数组

上面分析可以得到以下结论:
假设已经计算出子数组 a[1…i-2] 的最大子数组的和为 all[i-2],同时也计算出 a[0…i-1] 中包含 a[i-1] 的最大的子数组和为 end[i-1]。则可以得出如下关系:all[i-1]=max{end[i-1], a[i-1], all[i-1]}

package main

import (
	"fmt"
)

func Max(a, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}
func getMax(a []int) int {
	end := make([]int, len(a))
	all := make([]int, len(a))
	end[0] = a[0]
	all[0] = a[0]
	end[len(a)-1] = a[len(a)-1]
	all[len(a)-1] = a[len(a)-1]
	for i := 1; i < len(a); i++ {
		end[i] = Max(end[i-1]+a[i], a[i])
		all[i] = Max(end[i], all[i-1])
	}
	return all[len(a)-1]
}

func main() {
	arr := []int{1, -2, 4, 8, -4, 7, -1, -5}
	fmt.Println(getMax(arr))
}

改进的动态规划

func getMax(a []int) int {

	end := a[0] // 最大子数组和
	all := a[0] // 包含最后一个元素的最大子数组和

	for _, v := range a {
		end = Max(end+v, v)
		all = Max(end, all)
	}
	return all
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值