题目链接
题目描述
小红准备制作一个名为“岁晚可可塔”的甜品,由 层巧克力蛋糕组成。每一层蛋糕都有一个甜度值
:
- 如果
,表示这一层口感香甜。
- 如果
,表示这一层带有苦味。
为了保证口感的连贯性,小红需要从这 层蛋糕中切出一段连续的非空区间
作为最终成品,使得该段蛋糕的甜度总和最大。
请帮小红计算出这连续的一段蛋糕层所能达到的最大甜度总和。
解题思路
本题是经典的**最大子数组和(Maximum Subarray Sum)**问题,可以使用 Kadane's 算法 在 的时间复杂度内解决。
-
核心思想: 遍历数组,维护一个当前子数组的最大和
。对于每一个新元素
,我们面临两个选择:
- 将
加入到当前的子数组中:
。
- 以
为起点开启一个新的子数组:
。 因此,更新公式为:
。
- 将
-
维护全局最大值: 在遍历过程中,不断更新全局最大值
。
-
注意点:
- 题目要求区间必须是非空的。
- 甜度值
的范围在
之间,
最大为
,因此总和可能超过
,需要使用 64 位整数存储(C++ 中的
long long,Java 中的long)。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
// 读取蛋糕总层数
cin >> n;
vector<long long> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
// Kadane's 算法初始化
long long current_sum = a[0];
long long ans = a[0];
for (int i = 1; i < n; ++i) {
// 对于每一层,决定是接在前面的序列后面,还是重新开始
current_sum = max(a[i], current_sum + a[i]);
// 更新全局最大甜度总和
ans = max(ans, current_sum);
}
cout << ans << endl;
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 读取总层数 N
int n = sc.nextInt();
long[] a = new long[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextLong();
}
// 初始化:ans 和 currentSum 都设为第一层的值
long currentSum = a[0];
long ans = a[0];
for (int i = 1; i < n; i++) {
// 状态转移:取当前值或当前值与之前和的累加值中的较大者
currentSum = Math.max(a[i], currentSum + a[i]);
// 更新结果
ans = Math.max(ans, currentSum);
}
System.out.println(ans);
}
}
def solve():
# 读取输入
n = int(input())
a = list(map(int, input().split()))
# Kadane's 算法
# 初始化为第一个元素,确保区间非空
current_sum = a[0]
ans = a[0]
for i in range(1, n):
# 决定当前层是否加入前面的连续段
if current_sum > 0:
current_sum += a[i]
else:
current_sum = a[i]
# 更新全局最大值
if current_sum > ans:
ans = current_sum
print(ans)
solve()
算法及复杂度
- 算法:Kadane's 算法(动态规划)。
- 时间复杂度:
。只需对
层蛋糕进行一次线性遍历。
- 空间复杂度:
。主要是用于存储
层蛋糕甜度值的数组。若采用边读取边处理的方式,空间复杂度可优化至
。

京公网安备 11010502036488号