LeetCode/最大子数组和
给你一个整数数组nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组是数组中的一个连续部分。
1. 暴力法(超时)
三重循环(列所有数组)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n=nums.size();
int max_=nums[0];
int temp;
for(int len=1;len<=n;len++){
for(int i=0;i<=n-len;i++){
temp =0;
for(int j=i;j<i+len;j++){
temp=temp+nums[j];
}
max_=max(max_,temp);
}
}
return max_;
}
};
从前往后遍历过程的一次过程中,相当于每一趟比较了所有以i开头的连续数组的最大和,
把所有开头的连续数组比较完即可,时间复杂度为O(n2)
其实可以从后往前遍历,相当于写成每一趟比较以i结尾的连续数组
二重循环
class Solution
{
public:
int maxSubArray(vector<int> &nums)
{
//类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
int max = INT_MIN;
int numsSize = int(nums.size());
for (int i = 0; i < numsSize; i++)
{
int sum = 0;
for (int j = i; j < numsSize; j++)
{
sum += nums[j];
if (sum > max)
{
max = sum;
}
}
}
return max;
}
};
2. 动态规划
数组没有方向,所以从前往后和从后往前缩小问题规模,没有什么差别
那么要如何缩小问题规模呢?
假定从前往后的话,要使得评估长度i和i+1数组的方程产生联系
注意到题目中的连续数组,所以可以设dp[i]表示为以nums[i]结尾的连续子数组最大和
这样我们既能完成状态的转移,又能对所有数组进行有效的评估
状态转移方程为dp[i]=max(nums[i],dp[i-1]+nums[i])
边界条件:dp[0]=nums[0]
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n=nums.size();
int max_=INT_MIN;
vector<int> dp(n);
dp[0]=nums[0];
for(int i=1;i<n;i++)
dp[i]=max(nums[i],dp[i-1]+nums[i]);
for(int i=0;i<n;i++)
max_=max(max_,dp[i]);
return max_;
}
};
滚动变量空间优化
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int max_=INT_MIN;
int dp;
max_=dp=nums[0];
for(int i=1;i<nums.size();i++){
dp=max(nums[i],dp+nums[i]);
max_=max(max_,dp);
}
return max_;
}
};
同样可以从后往前遍历,状态设dp[i]表示为以nums[i]开头的连续子数组最大和
状态转移方程为dp[i]=max(nums[i],dp[i+1]+nums[i])
边界条件:dp[0]=nums[n-1]