leetode第53题
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
方法一:暴力法
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n=nums.size();
int res=-1000000;
for(int i=0;i<n;i++)
{
//统计从i到j的子数组的和
int sum=0;
for(int j=i;j<n;j++)
{
sum=sum+nums[j];
//保留最大值
res=max(res,sum);
}
}
return res;
}
};
时间复杂度O(n^2)空间复杂度O(1)
方法二:贪心算法
对于每一个数来说,上一个和是正数,才能越加越大,否则无论怎么加都会变小,所以如果上一个和是负数的话,直接从这个数重新开始找连续和就行了
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int sum=0,res=nums[0];
//贪心算法
for(int i=0;i<nums.size();i++)
{
//如果前面的数的和为负数,那直接舍去。从这个数开始加,因为一个数加负数会变小
if(sum<0)
{
sum=nums[i];
}
//前面的数字的和是正数,那就加上第i位数字
else{
sum=sum+nums[i];
}
//结果存储的是加上第i位数字和不加第i位数字的最大值
res=max(sum,res);
}
return res;
}
};
时间复杂度:O(N),空间复杂度O(1)
方法三:分治法
class Solution {
public:
int maxSubArray(vector<int>& nums) {
return getmax(nums,0,nums.size()-1);
}
//求包含了第mid个数和第mid+1个数那部分的最大子数组
//求左边的最大子数组和右边的最大子数组
int getMIdMax(vector<int>& nums,int mid,int left,int right)
{
//先求左边那部分的最大子数组
int leftSum=-10000000;
int sum=0;
for(int i=mid;i>=left;i--)
{
sum=sum+nums[i];
if(sum>leftSum)
leftSum=sum;
}
//求右边那部分的最大子数组
int rightSum=-10000000;
sum=0;
for(int i=mid+1;i<=right;i++)
{
sum=sum+nums[i];
if(sum>rightSum)
rightSum=sum;
}
return leftSum+rightSum;
}
int getmax(vector<int>& nums,int left,int right)
{
if(left==right)
return nums[left];
int mid=(left+right)/2;
//连续子数组三种情况,一种是最大值在数组的左半部分,一种是最大值在数组的右半部分,一种是包含了第mid个数和第mid+1
return max(max(getmax(nums,left,mid),getmax(nums,mid+1,right)),getMIdMax(nums,mid,left,right));
}
};
方法四:动态规划
class Solution {
public:
int maxSubArray(vector<int>& nums) {
//dp[i]=到i的最大子数和
int n=nums.size();
vector<int> dp(n,0);
dp[0]=nums[0];
int maxSum=dp[0];
for(int i=1;i<n;i++)
{
//对于每个数有两种情况,要么把当前数字加入子序列,要么重新开始,看哪个的值更大
dp[i]=max(dp[i-1]+nums[i],nums[i]);
maxSum=max(maxSum,dp[i]);
}
return maxSum;
}
};