C++最大子段和

最大子段和简介

题目描述:
给出一段序列,选出其中连续且非空的一段使得这段和最大。

输入格式:
第一行:是一个正整数N,表示了序列的长度。
第二行:包含N个整数num[i],描述了这段序列。

输出格式:
一个整数,为最大的子段和是多少。

输入样例:

7
2 -4 3 -1 2 -4 3

输出样例:

4

暴力解法

每当你看到一道题,第一个想的算法一定是暴力!

暴力么,很简单。分别枚举一段连续数列的首和尾,两重循环,之后让ans和(a[i] + a[i + 1] + a[i + 2] + … + a[j - 1] + a[j])取max就行了,当然也不能太暴力,得稍微优化一些:用一个前缀和sum数组记录一下,然后让ans和(sum[j] - sum[i - 1])取max就没问题了。

这样一算,时间复杂度也并不高。才On^2级别。

以下为暴力代码:
(PS:NR是数组个数的上限)

# include <cstdio>
# include <iostream>
# include <cmath>
# include <cstring>
# include <algorithm>
using namespace std;

# define FOR(i, a, b) for(int i = a; i <= b; i++)
# define _FOR(i, a, b) for(int i = a; i >= b; i--)

const int NR = 100000;

int n, ans = -2e9;
int num[NR + 10];
int sum[NR + 10];

int main()
{
	scanf("%d", &n);
	FOR(i, 1, n){
		scanf("%d", &num[i]);
		sum[i] = sum[i - 1] + num[i];
	}
	FOR(i, 1, n)
		FOR(j, i, n)
			ans = max(ans, sum[j] - sum[i - 1]);
	printf("%d\n", ans);
	return 0;
}

动态规划解法

提到DP,就一定就要去想:状态、转移方程、初值和答案了。

  1. 状态:dp[i]指在1~i这i个数中,加数必须有num[i]这个数的最大子段和。
  2. 转移方程:dp[i] = max(0, dp[i - 1]) + num[i];
    其实这个的意思就是:如果说在1~(i - 1)这(i - 1)个数中,加数必须有num[i - 1]这个数的最大子段和小于等于0,那么还不如说就不要前面的数,只来个num[i]就OK了。反之,若dp[i - 1]大于0,那么就让dp[i] = dp[i - 1] + num[i],这样可以更大些。(PS:其实就是分两种情况讨论,看哪种情况下答案更大便是了)。
  3. 初值:dp[i] = 0
  4. 答案:max{dp[i]}

这样时间复杂度就优化到On级别的算法了。

分析完这DP的四要素,就可以开始写代码了:

# include <cstdio>
# include <iostream>
# include <cmath>
# include <cstring>
# include <algorithm>
using namespace std;

# define FOR(i, a, b) for(int i = a; i <= b; i++)
# define _FOR(i, a, b) for(int i = a; i >= b; i--)

const int NR = 100000;

int n, ans = -2e9;
int num[NR + 10];
int dp[NR + 10];

int main()
{
	scanf("%d", &n);
	FOR(i, 1, n) scanf("%d", &num[i]);
	FOR(i, 1, n) dp[i] = max(dp[i - 1], 0) + num[i];
	FOR(i, 1, n) ans = max(dp[i], ans);
	printf("%d\n", ans);
	return 0;
}

God Bless You For Ever!

发布了33 篇原创文章 · 获赞 47 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/SkeletonKing233/article/details/93096044