高频算法面试题(十一)- 连续子数组的最大和

118 阅读4分钟

「这是我参与11月更文挑战的第 6 天,活动详情查看:2021最后一次更文挑战

刷算法题,从来不是为了记题,而是练习把实际的问题抽象成具体的数据结构或算法模型,然后利用对应的数据结构或算法模型来进行解题。个人觉得,带着这种思维刷题,不仅能解决面试问题,也能更多的学会在日常工作中思考,如何将实际的场景抽象成相应的算法模型,从而提高代码的质量和性能,更能锻炼思维

连续子数组的最大和

题目来源LeetCode-剑指 Offer 42. 连续子数组的最大和

题目描述

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)

示例

示例 1

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

提示:

  • 1 <= arr.length <= 10^5
  • 100 <= arr[i] <= 100

解题

解法一:暴力解法

思路

暴力解法的思路很简单,只要我求出来所有的子序列的和,然后取最大的那个就可以了。直接上代码

代码

//暴力解法
func MaxSubArray2(nums []int) int {
	n := len(nums)
	if n == 0 {
		return -1
	}
	if n==1 {
		return nums[0]
	}
	max := nums[0]
	for i := 0; i < n-1; i++ {
		sum := 0
		for j := i; j < n; j++ {
			sum += nums[j]
			if sum > max {
				max = sum
			}
		}
	}

	return max
}

解法二:动态规划解法

思路

一般看到求最优解的问题,都会想到贪心算法和动态规划。而贪心算法并不能总是给出最优解,所以这道题很容易想到用动态规划来解题

什么样的题适合用动态规划来解?动态规划能解决的问题有什么规律可循?

总结为:一个模型三个特征

一个模型:多阶段决策最优解模型

一般是用动态规划来解决最优问题。而解决问题的过程,需要经历多个决策阶段。每个决策阶段都对应着一组状态。然后我们寻找一组决策序列,经过这组决策序列,能够产生最终期望求解的最优值

三个特征

  1. 最优子结构 最优子结构指的是,问题的最优解包含子问题的最优解。反过来说就是,我们可以通过子问题的最优解,推导出问题的最优解。也可以理解为,后面阶段的状态可以通过前面阶段的状态推导出来
  2. 无后效性 无后效性有两层含义,第一层含义是,在推导后面阶段的状态的时候,我们只关心前面阶段的状态值,不关心这个状态是怎么一步一步推导出来的。第二层含义是,某阶段状态一旦确定,就不受之后阶段的决策影响。无后效性是一个非常“宽松”的要求。只要满足前面提到的动态规划问题模型,其实基本上都会满足无后效性
  3. 重复子问题 不同的决策序列,到达某个相同的阶段时,可能会产生重复的状态

来自《数据结构与算法之美》

了解了适合用动态规划解决的问题的特点,可以看一下本题,它首先是一个求最优解的问题(不是说所有的最优解问题都用动态规划来解,只是说它应该在我们的考虑范围之内)

本题要求的是连续子数组的最大值,看能不能套用动态规划里边的最优子结构这一特征。假设要求0 ~ 5这段下标的连续数据的最大和,那只要知道下标0 ~ 4这段连续数组的最大和其实就可以了,为什么?

假设0~4这段连续子数组的最大和为n,如果n+arr[5] > arr[5],那n + arr[5]不就是0 ~ 5这段下标的连续数据的最大和吗?所以,其实就是可以根据前边的最优解,推出后边这个的最优解

所以,假设数组长度是n。那我推出下标01的最大连续子序列的和,也就是知道了下标02的最大连续子序列的和,直到0~n

有了上边这个思路,代码就很好写了

代码

// 连续子数组的最大和
func MaxSubArray(nums []int) int {
	n := len(nums)
	if n == 0 {
		return -1
	}
	if n==1 {
		return nums[0]
	}

	maxSum := nums[0]
	for i:=1; i < n; i++ {
		if nums[i] + nums[i-1] > nums[i] {
			nums[i] += nums[i-1] //注意,这就将num[i]位置的值,保存成了0~i这个子序列的最大和(相当于记录了0~i这段连续子数组的状态(最大和))
		}
		if nums[i] > maxSum {
			maxSum = nums[i]
		}
	}

	return maxSum
}