最大子序列和问题
求数组的最大子序列和
方法一
给定了一个数组让我们求他的最大子序列和,我们最容易想到的方法就是暴力枚举的方式
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int thisMax = 0, sumMax = nums[0];
int len = nums.size();
for(int i = 0; i < len; ++i){
thisMax = 0;
for(int j = i; j < len; ++j){
thisMax += nums[j];
sumMax = max(sumMax, thisMax);
}
}
return sumMax;
}
};
上述的时间复杂度为O(N^2),当数据量很大的时候就会非常的慢
方法二
利用分治的方式,将数组不断的递归划分成子问题。最大的会等于左边的、右边的、跨边界的三者之一
int getMax(int arr[], int l, int r){
if(l >= r){
return arr[l];
}
int mid = l + r >> 1;
int maxLeft = getMax(arr, l, mid);
int maxRight = getMax(arr, mid + 1, r);
//因为要跨边界,所以直接从边界处扫描过去,所以下面就是从mid处一路扫描过去的最大值(这里的最大值是会和边界连续的)
int maxLeft1 = arr[mid], thisMax = 0;
for(int i = mid; i >= l; --i){
thisMax += arr[i];
maxLeft1 = max(maxLeft1, thisMax);
}
thisMax = 0; int maxRight1 = arr[mid + 1];
for(int i = mid + 1; i <= r; ++i){
thisMax += arr[i];
maxRight1 = max(maxRight1, thisMax);
}
int t = maxLeft1 + maxRight1;
return (maxLeft > maxRight? (maxLeft > t? maxLeft : t) : (maxRight > t? maxRight : t));
}
时间复杂度为:O(NlogN)
方法三
利用Kadane算法(也就是动态规划)
当前面的子序列和小于0的时候就不用了舍弃掉,用也只会使得后续序列变小,重新选择起点的意思。
每一步都进行最大值的比较,这样即使系列和没有以前的大,也会使得前面序列和的值保存了到最大值变量中。
int getMax(int arr[], int n){
int maxSum = arr[0];
for(int i = 1; i < n; ++i){
if(arr[i - 1] > 0) arr[i] += arr[i - 1];//大于0的加的有意义
maxSum = max(maxSum, arr[i]);
}
return maxSum;
}
或
int getMax(int arr[], int n){
int maxSum = arr[0], thisMax = arr[0];
for(int i = 1; i < n; ++i){
thisMax = max(thisMax + arr[i], arr[i]);//意思就是,如果thisMax使得arr[i]变小了,就不取他,让thisMax重新选择起点
maxSum = max(thisMax, maxSum);
}
return maxSum;
}
上述两种是一个意思,第一个是在数组原地操作,而第二个多用了一个临时变量
时间复杂度为:O(N),是线性的
如有错误,欢迎指正!