问题介绍
最大子数组问题可以由如下问题引出:
假设有一段股票价格曲线,我们的目的是寻找一段日期,使得第一天到最后一天的股票价格净变值最大,在实际应用中可以用于求获取最大利益的方案。
最大子数组问题,也就是寻找数组A的和最大的非空连续子数组,我们称这样的数组为最大子数组(maximum subarray),可以使用暴力求解、分治法、Kadane算法、动态规划法等进行求解,在这里介绍分治法进行求解,时间复杂度
分治法
使用分治策略,不断递归将数组从中央位置一分为二,分别求左边、右边、跨越中央位置的最大子数组,进行比较得出结果。
伪代码如下所示:
Tips
使用C++进行算法求解需要注意以下几点:
(1)因为每次需要返回子数组的头尾下标以及子数组之和,所以使用std::tuple数据结构将这三个成员绑定在一起,使用头文件<tuple>
相关用法:
①定义tuple:tuple<type1, type2, type3> tupleName;
例如:tuple<int, int, double> A;
②将三个数绑定为tuple:make_tuple()
例如:tuple<int, int, int> A = make_tuple(a, b, c);
③获取tuple元素:get<number>(tupleName);
例如:int sum = get<2>(A);
(2)在计算数组中央位置时,需要对头尾中位数向下取整,使用floor()返回小于传入参数的最大整数,使用头文件<math.h>,类似的ceil()能够返回大于传入参数的最小整数
例如:mid = floor((low+high)/2)
/* 最大子数组问题 Author:lsftt*/
#include<iostream>
#include<tuple>
#include<math.h>
#include<limits.h>
using namespace std;
// 寻找跨越中点的最大子数组
tuple<int, int, int> Find_Max_Crossing_Subarray(int A[], int low, int mid, int high){
int sum = 0;
int left_sum = INT_MIN; int right_sum = INT_MIN;
int max_left, max_right;
for(int i = mid; i > low; i--){
sum += A[i];
if(sum > left_sum){
left_sum = sum;
max_left = i;
}
}
for(int i = mid + 1; i < high; i++){
sum += A[i];
if(sum > right_sum){
right_sum = sum;
max_right = i;
}
}
tuple<int, int, int> result = make_tuple(max_left, max_right, left_sum + right_sum);
return result;
}
// 寻找最大子数组
tuple<int, int, int> Find_Maximum_Subarray(int A[], int low, int high){
tuple<int, int, int> result_low; tuple<int, int, int> result_high; tuple<int, int, int> result_cross; // low, high, sum
int mid;
if(high == low){ // 只有一个元素
result_low = make_tuple(low, high, A[low]);
return result_low;
}
else{
mid = floor((low + high) / 2);
result_low = Find_Maximum_Subarray(A, low, mid); // 左半边
result_high = Find_Maximum_Subarray(A, mid + 1, high); // 右半边
result_cross = Find_Max_Crossing_Subarray(A, low, mid, high); // 中间
}
// 进行比较,获得最大子数组
if(get<2>(result_low) >= get<2>(result_high) && get<2>(result_low) >= get<2>(result_cross)){
return result_low;
}
else if(get<2>(result_high) >= get<2>(result_low) && get<2>(result_high) >= get<2>(result_cross)){
return result_high;
}
else return result_cross;
}
// 生成随机数组
void generate_A(int A[], int N){
for(int i = 0; i < N; i++) A[i] = rand();
}
int main(){
int N = 50;
int low = 0;
int high = N;
int A[50];
generate_A(A, N);
tuple<int, int, int> result = Find_Maximum_Subarray(A, low, high);
cout << "The Maximum Subarray:" << endl;
for(int i = get<0>(result); i < get<1>(result); i++) cout << A[i] << " ";
cout << endl;
cout << "Sum: " << get<2>(result);
return 0;
}