给定一个实数序列,设计一个最有效的算法,找到一个总和数最大的区间
#include <iostream>
#include <vector>
#include <limits>
// 结果结构体,用于存储最大子数组的信息
struct Result {
int maxSum; // 最大和
int start; // 子数组的起始索引
int end; // 子数组的结束索引
};
// 查找最大子数组的函数,基于 Kadane 算法
Result findMaxSubarray(const std::vector<double>& arr) {
double maxSoFar = std::numeric_limits<double>::lowest(); // 初始化最大和为负无穷
double maxEndingHere = 0; // 当前子数组的和
int start = 0, end = 0, s = 0; // 记录最大子数组的起始和结束索引
Result result; // 创建结果对象
result.maxSum = 0; // 初始化结果的最大和为0
result.start = 0; // 初始化结果的起始索引为0
result.end = 0; // 初始化结果的结束索引为0
for (int i = 0; i < arr.size(); i++) {
maxEndingHere += arr[i]; // 将当前元素加入当前子数组和
if (maxSoFar < maxEndingHere) {
maxSoFar = maxEndingHere; // 更新最大和
start = s; // 更新起始索引
end = i; // 更新结束索引
}
if (maxEndingHere < 0) {
maxEndingHere = 0; // 如果当前子数组和为负数,重新开始计算子数组和
s = i + 1; // 更新起始索引
}
}
result.maxSum = maxSoFar; // 将最大和存入结果对象
result.start = start; // 将起始索引存入结果对象
result.end = end; // 将结束索引存入结果对象
return result; // 返回结果对象
}
int main() {
std::vector<double> arr = {-2.0, 1.0, -3.0, 4.0, -1.0, 2.0, 1.0, -5.0, 4.0};
Result result = findMaxSubarray(arr);
std::cout << "最大连续子数组的和为 " << result.maxSum << std::endl;
std::cout << "起始索引: " << result.start << std::endl;
std::cout << "结束索引: " << result.end << std::endl;
return 0;
}
算法思想:
- Kadane算法的核心思想是动态规划。我们通过一次遍历数组就能找到最大子数组和。
- 我们维护两个变量:
maxSoFar
:到目前为止找到的最大子数组和maxEndingHere
:以当前元素结尾的最大子数组和
- 对于每个元素,我们有两个选择:
- 将当前元素加入到现有的子数组中
- 开始一个新的子数组
- 如果
maxEndingHere
变为负数,我们就重置它为0,因为没有理由保留一个负的子数组和。 - 我们还跟踪最大子数组的起始和结束索引。
代码解释:
- 我们定义了一个
Result
结构来存储最大和及其对应的起始和结束索引。 findMaxSubarray
函数实现了Kadane算法:- 初始化
maxSoFar
为最小的可能值,maxEndingHere
为0。 - 遍历数组,更新
maxEndingHere
和maxSoFar
。 - 当找到一个新的最大和时,更新起始和结束索引。
- 如果
maxEndingHere
变为负数,重置它并更新潜在的新起始索引。
- 初始化
- 在
main
函数中,我们展示了如何使用这个算法。
这个算法的时间复杂度是O(n),其中n是数组的长度,因为我们只需要遍历数组一次。空间复杂度是O(1),因为我们只使用了常数额外空间。
这个算法非常高效,它能在一次遍历中找到最大子数组和,而不需要考虑所有可能的子数组(这将需要O(n^2)的时间复杂度)。