给定一个实数序列,设计一个最有效的算法,找到一个总和数最大的区间
#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; // 初始化结果的最大和为0result.start = 0; // 初始化结果的起始索引为0result.end = 0; // 初始化结果的结束索引为0for (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)的时间复杂度)。