给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
1.使用动态规划:
对于该问题,假设以nums[i]结尾的最大连续子序列为dp[i],那么存在下列两种情况:
1,最大连续子序列为nums[i]本身,即只存在一个元素,此时dp[i]=nums[i];
2,最大连续子序列是nums[i]+dp[i-1],其中dp[i-1]为nums[i-1]结尾的最大连续子序列和,此时d[i]=nums[i]+dp[i-1]。
因为以nums[i]结尾的最大连续子序列的末尾元素只能为nums[i],故仅存在上述两种情况,故可总结出状态转移方程:
dp[i] = max(nums[i], nums[i] + dp[i-1])
对应的代码如下:
(1)提前处理i=0的情况:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT_MIN;
int current_dp = nums.at(0), last_dp = nums.at(0);
result = nums.at(0); //需要特别注意i=0的情况,否则全部是负数就出错
for (int i = 1; i < nums.size(); ++i) {
current_dp = std::max(nums.at(i), last_dp + nums.at(i));
last_dp = current_dp; //可以优化只是用一个变量
if (current_dp > result) {
result = current_dp;
}
}
return result;
}
};
(2)单独处理i=0的情况:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT_MIN;
int current_dp = nums.at(0), last_dp = nums.at(0);
int temp_sum = 0;
for (int i = 0; i < nums.size(); ++i) {
if (0 == i) { //单独处理第一个数字,保障全部都是负数正确,例如[-1,-2]
current_dp = nums.at(0);
last_dp = nums.at(0);
} else {
current_dp = std::max(nums.at(i), last_dp + nums.at(i));
last_dp = current_dp; //可以优化只是用一个变量
}
if (current_dp > result) {
result = current_dp;
}
}
return result;
}
};
2.使用贪心算法:
如果 temp_sum > 0
,则说明 temp_sum 对结果有增益效果,则 temp_sum 保留并加上当前遍历数字
如果 temp_sum <= 0
,则说明 temp_sum 对结果无增益效果,需要舍弃,则 temp_sum 直接更新为当前遍历数字
每次比较 temp_sum 和 result
的大小,将最大值置为result
,遍历结束返回结果
对应的代码如下:
class Solution
{
public:
int maxSubArray(vector<int> &nums) {
int result = INT_MIN;
int temp_sum = 0;
for (int i = 0; i < nums.size(); i++) {
temp_sum += nums[i]; //只要和大于0,都有希望超于最大值
result = max(result, temp_sum);
//如果temp_sum < 0,重新开始找子序串
if (temp_sum < 0) { //代表之前的数据贡献为负,需要重置
temp_sum = 0;
}
}
return result;
}
};