【知识点2】最大连续子序列和⭐⭐⭐⭐⭐

机试不会考裸的最大连续子序列和,而是会考一些变形,可能需要自己去转换成最大连续子序列和,要灵活变通,不要以为背了模板就没事了,比如这里的题型训练我就没想到用最大连续子序列和🤦‍

今天也是为了cc,努力奋斗的一天ヾ(≧▽≦*)o

1. 问题描述

最大连续子序列和问题如下:

给定一个数字序列 A 1 A_1 A1, A 2 A_2 A2,…, A n A_n An,求i,j(1≤i≤j≤n),使得 A i A_i Ai+…+ A j A_j Aj最大,输出这个最大和。

在这里插入图片描述

2. 暴力解决方案

在这里插入图片描述

3. 动态规划解决方案

下面介绍动态规划的做法,复杂度为 O ( n ) O(n) O(n)

3.1 步骤1——状态定义

状态dp[i]表示以A[i]作为末尾的连续序列的最大和(这里是说A[i]必须作为连续序列的末尾)。

其实与我们的LIS的dp数组的定义很像很像,都是以XX结尾的。

以样例为例:序列-2 11 -4 13 -5 -2,下标分别记为0,1,2,3,4,5,那么
在这里插入图片描述
通过设置这么一个dp数组,要求的最大和其实就是dp[0],dp[1],…,dp[n-1]中的最大值(因为到底以哪个元素结尾未知),下面想办法求解dp数组。

3.2 步骤2——状态转移方程

作如下考虑,因为dp[i]要求是必须以A[i]结尾的连续序列,那么只有两种情况:

  1. 这个最大和的连续序列只有一个元素,即以A[i]开始,以A[i]结尾。
  2. 这个最大和的连续序列有多个元素,即从前面某处A[p]开始(p<i),一直到A[i]结尾。

对于情况1,最大和就是A[i]本身。
对于情况2,最大和是dp[i-1]+A[i],即A[p]+...+A[i-1]+A[i] = dp[i-1] + A[i]。由于只有这两种情况,于是得到状态转移方程

dp[i] = max{ A[i] , dp[i-1]+A[i] }

这个式子只和i和i之前的元素有关,且边界为dp[0]=A[0],由此从小到大枚举i,即可得到整个dp数组。接着输出dp[0],dp[1],…,dp[n-1]中的最大值即为最大连续子序列的和。

怎么样,是不是很神奇?只用 O ( n ) O(n) O(n)的时间复杂度就解决了原先需要 O ( n 2 ) O(n^2) O(n2)复杂度问题,这就是动态规划的魅力。

4. 代码

#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn = 10010;

int A[maxn],dp[maxn];	//A[i]存放以A[i]结尾的连续序列的最大和

int main(){
	int n;
	scanf("%d",&n);
	
	for(int i=0;i<n;++i){	//读入序列 
		scanf("%d",&A[i]); 
	}
	
	//边界
	dp[0] = A[0];
	
	for(int i=1;i<n;++i){
		//状态转移矩阵
		dp[i] = max(A[i],A[i]+dp[i-1]); 
	}
	
	//dp[i]存放以A[i]结尾的连续序列的最大和,需要遍历i得到最大的才是结果
	int k=0;
	for(int i=1;i<n;++i){
		if(dp[i] > dp[k]){
			k = i;
		}
	}
	
	printf("%d\n",dp[k]);
	return 0; 
} 

5. 状态的无后效性⭐⭐⭐⭐⭐

状态的无后效性:

  • 当前状态记录了历史信息,一旦当前状态确定,就不会再改变,且未来的决策只能在已有的一个或若干个状态的基础上进行,历史信息只能通过已有的状态去影响未来的决策。

例如:

  • 宇宙的历史可以看作一个关于时间的线性序列,对每一个时刻来说,宇宙的现状就是这个时刻的状态,显然宇宙过去的信息蕴含在当前状态中,并只能通过当前状态来影响下一个状态,因此从这个角度来说宇宙的关于时间的状态具有无后效性。
  • 针对本节的问题来说,每次计算状态dp[i],都只会涉及dp[i-1],而不直接用到dp[i-1]蕴含的历史信息。

对动态规划可解的问题,总会有很多涉及状态的方式,但并不是所有状态都具有无后效性,因此必须设计一个拥有无后效性的状态以及相应的状态转移方程,否则动态规划就没有办法得到正确结果。事实上, 如何设计状态和状态转移方程,才是动态规划的核心,而它们也是动态规划最难的地方。

做DP题的关键,就是寻找一个好的状态。

总结一下,动态规划问题的时间复杂度由两部分组成:状态数量和状态转移复杂度,往往程序总的复杂度为它们的乘积。

6. 题型训练

  1. ⭐【最大连续子序列和】A - Sum

7. 参考文档

算法笔记

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值