题号 53
题目描述
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
解题思路1——暴力法
1- 设定两个指针 :
maxSub 用于存储当前已经找到的连续子数组的最大和,初值为给定数组的第一个数的值
nowSub 用于存储目前遍历的连续子数组的和,初值为0
2- 对于数组中的每一个元素 i 进行如下的循环:
如果 nums[i] 的值比 maxSub 大,则将其赋值给 maxSub;
如果该元素是数组中的最后一个元素,则直接返回 nums[i] 和 maxSub中较大的一个,循环结束;
否则:
将 nums[i] 赋值给 nowSub,令 j 指向 i 的下一个元素,当 j < nums.size() 时,进行如下的循环:
(1)将 nums[j] 加到 nowSub
(2)如果 nowSub 大于 maxSub,则将其值赋值给maxSub
(3)j ++
3- 返回 maxSub
时间复杂度:O(n^2)
空间复杂度:O(1)
代码实现:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
vector<int> ans;
int maxSub = nums[0], nowSub = 0;;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > maxSub)
maxSub = nums[i];
if (i == nums.size() - 1) {
return maxSub;
}
nowSub = nums[i];
int j = i + 1;
while (j < nums.size()) {
nowSub += nums[j];
j++;
if (nowSub > maxSub) {
maxSub = nowSub;
}
}
}
return maxSub;
}
};
解题思路2——动态规划
Step1、2:描述问题的最优解结构特征、递归定义最优解值
对于以 nums[ i ] 结尾的所有连续子数组而言,使用 dp[ i ] 记录以 nums[ i ] 结尾的所有连续子数组中的最大和。
1- 底:dp[ 0 ] = nums[ 0 ];
2- 根据定义,dp[ i - 1 ] 存放了以 nums[ i - 1 ] 结尾的所有连续子数组中的最大和
如果 dp[ i - 1 ] + nums[ i ] > nums[ i ], 则显然 nums[ i ] 与其前面的已经计算得到的具有最大和的连续子数组共同构成新的具有最大和的连续子数组;否则,nums[ i ] 自身就是具有最大和的连续子数组【只包含 nums[ i ] 一个元素】
因此,dp[ i ] = max { dp[ i - 1] + nums[ i ], nums [ i ] }
3- 设定一个指针 max ,用于存放结果,初值为 nums[ 0 ],对于每一个元素,都比较 dp[ i ] 和 max 的值,如果前者大于后者,则将前者赋值给后者即可
4- 返回 max
Step3:自底向上计算最优解值
class Solution {
public:
int maxSubArray(vector<int>& nums) {
vector<int> dp; //用于记录以nums[i]结尾的所有连续子数组中的最大和
dp.push_back(nums[0]); //底:dp[0]=nums[0]
int ans = 0, max = nums[0]; //max用于记录结果
for (int i = 1; i < nums.size(); i++) { //对于给定数组中的每一个元素,进行如下循环
if (dp[i - 1] + nums[i] > nums[i]) { //dp[i]= dp[i-1]+nums[i]和nums[i]中较大的一个
ans = dp[i - 1] + nums[i];
}
else {
ans = nums[i];
}
dp.push_back(ans);
if (ans > max) { //max存储目前找到的所有连续子数组中的最大和
max = ans;
}
}
return max;
}
};
时间复杂度:O(n)
空间复杂度:O(n)