题目链接
题目描述
给定一个长度为 的整数数组
。请你从中选取一个非空子数组(连续的一段),使得其元素之和最大。求出该最大和。
解题思路
本题是经典的动态规划问题,通常使用“Kadane算法”来高效解决。
我们定义 为以数组中第
个元素
结尾的连续子数组的最大和。我们的目标是求出所有
中的最大值。
对于第 个元素,以它结尾的最大和子数组有两种可能:
- 子数组只包含
这一个元素。
- 子数组是在以
结尾的最大和子数组后面,再接上
形成的。
因此,我们可以得到状态转移方程:
这个方程的含义是:以 结尾的最大子数组和,要么是
本身(这意味着开启一个新的子数组),要么是
加上前一个元素结尾的最大子数组和(这意味着延续之前的子数组)。
我们只需要一个变量来记录全局的最大和。在遍历数组计算每个 的同时,我们用一个全局最大值变量来更新和保留历史上的最大
值。
在实现时,可以发现计算 只需要
的值。因此,我们不需要一个完整的
数组,只需要一个变量来记录“当前结尾的最大和”即可,从而将空间复杂度优化到
。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
vector<long long> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
// current_max 相当于 dp[i],max_so_far 是全局最大值
long long current_max = a[0];
long long max_so_far = a[0];
for (int i = 1; i < n; i++) {
current_max = max(a[i], current_max + a[i]);
max_so_far = max(max_so_far, current_max);
}
cout << max_so_far << "\n";
return 0;
}
import java.util.Scanner;
import java.lang.Math;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long[] a = new long[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextLong();
}
// currentMax 相当于 dp[i],maxSoFar 是全局最大值
long currentMax = a[0];
long maxSoFar = a[0];
for (int i = 1; i < n; i++) {
currentMax = Math.max(a[i], currentMax + a[i]);
maxSoFar = Math.max(maxSoFar, currentMax);
}
System.out.println(maxSoFar);
}
}
n = int(input())
a = list(map(int, input().split()))
# current_max 相当于 dp[i],max_so_far 是全局最大值
current_max = a[0]
max_so_far = a[0]
for i in range(1, n):
current_max = max(a[i], current_max + a[i])
max_so_far = max(max_so_far, current_max)
print(max_so_far)
算法及复杂度
- 算法:动态规划(Kadane算法)
- 时间复杂度:
,因为我们只需要对数组进行一次遍历。
- 空间复杂度:
,我们只使用了常数个额外变量来存储状态。