版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_30440627/article/details/54924737
给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。
样例
给出数组[−2,2,−3,4,−1,2,1,−5,3]
,符合要求的子数组为[4,−1,2,1]
,其最大和为6
1、找出子数组的最左端点 for i<-1 to n
2、找出子数组的最右端点 for j<-i to n
3、求和,找出最大值 sum = a[i] +……+a[j]; ans = max(ans, sum)
class Solution {
public:
/**
* @param nums: A list of integers
* @return: A integer indicate the sum of max subarray
*/
int maxSubArray(vector<int> nums) {
// write your code here
int n = nums.size();
int ans = -1000000; //因为求最大值,所以给结果初始化一个很小的数
for(int i=0; i<n; i++)
{
for(int j=i; j<n; j++)
{
int sum = 0;
for(int k=i; k<=j; k++)
{
sum += nums[k];
}
if(sum > ans)
{
ans = sum;
}
}
}
return ans;
}
};
但是很明显时间复杂度太大,只是作为一种最基础的方法,在此基础上再考虑优化方法。
慢在哪里?找冗余操作,执行次数最多的操作。求和操作被执行了很多次,有很多是重复计算的。
方法二 :优化枚举,时间复杂度O(n2)
左端点相同的子数组,随着长度的增加,排在前面的元素被不断重复相加。如果我们记录下之前的求和结果,
就不需要对前面的元素再进行计算,比方法一少了一重循环。
class Solution {
public:
/**
* @param nums: A list of integers
* @return: A integer indicate the sum of max subarray
*/
int maxSubArray(vector<int> nums) {
// write your code here
int n = nums.size();
int ans = -1000000;
for(int i=0; i<n; i++)
{
int sum = 0;
for(int j=i; j<n; j++)
{
sum += nums[j];
if(sum > ans)
{
ans = sum;
}
}
}
return ans;
}
};
显然O(n2)的复杂度还是不令人满意。继续寻找冗余操作。
如果子串A的和是负数,而子串B包含子串A,那B则不需要进行计算。这样就省去了一些计算步骤。
方法三:贪心法,复杂度O(n)
将子串和为负数的子串丢掉,只留和为正的子串。
class Solution {
public:
/**
* @param nums: A list of integers
* @return: A integer indicate the sum of max subarray
*/
int maxSubArray(vector<int> nums) {
// write your code here
int n = nums.size();
int ans = -1000000;
int sum = 0;
for(int i=0; i<n; i++)
{
sum += nums[i];
if(sum > ans)
{
ans = sum;
}
if(sum < 0)
{
sum = 0; //子串和为负数,丢掉
}
}
return ans;
}
};