剑指 Offer 42. 连续子数组的最大和
作者:互联网
剑指 Offer 42. 连续子数组的最大和
题目链接: 剑指 Offer 42. 连续子数组的最大和
有关题目
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。
求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
提示:
1 <= arr.length <= 10^5
-100 <= arr[i] <= 100
题解
法一:暴力法
class Solution
{
public:
int maxSubArray(vector<int> &nums)
{
//类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
//考察为以第i个元素起始的连续子数组的最大和
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;
}
};
法二:动态规划
思路:
动态规划求出每个位置的pre[i],返回数组pre中的最大值就好
int maxSubArray(int* nums, int numsSize){
int pre[numsSize];//pre[i]表示nums中以nums[i]结尾的最大子序和
int res = nums[0];
//类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
for (int i = 0; i < numsSize; i++)
{
pre[i] = -100;//题干给的条件,pre元素全部初始化最小值
}
pre[0] = nums[0];//初始化
for (int i = 1; i < numsSize; i++)
{
pre[i] = fmax(pre[i - 1] + nums[i], nums[i]);//动态转移方程
res = fmax(res,pre[i]);//由于我们定义的动态转移的意义为以nums[i]结尾的最大子序和
//我们添加一个变量来记录最大值
}
return res;
}
法三:滚动数组
int maxSubArray(int* nums, int numsSize){
int pre = 0, maxAns = nums[0];
for (int i = 0; i < numsSize; ++i)
{
pre = fmax(pre + nums[i], nums[i]);//前第i - 1项中的最大值加上当前项 与 第i项比较
maxAns = fmax(pre, maxAns);//存储出现的最大值
}
return maxAns;
}
法四:贪心
思路:
我们''贪心''的关键点在sum是否小于0
int maxSubArray(int* nums, int numsSize){
int maxAns = nums[0];
int sum = 0;
for (int i = 0; i < numsSize; i++)
{
sum += nums[i];
maxAns = fmax(maxAns,sum);
if (sum < 0) sum = 0;
}
return maxAns;
}
法五:分治
//对于一个区间[l,r],我们可以维护四个量:
//lSum表示[l,r]内以 l 为左端点的最大子段和
//rSum 表示 [l,r] 内以 r 为右端点的最大子段和
//mSum 表示 [l,r] 内的最大子段和
//iSum 表示 [l,r] 的区间和
struct Status {
int lSum, rSum, mSum, iSum;
};
//如何维护lSum, rSum, mSum, iSum
struct Status pushUp(struct Status l, struct Status r){
int iSum = l.iSum + r.iSum;
int lSum = fmax(l.lSum, l.iSum + r.lSum);
int rSum = fmax(r.rSum, r.iSum + l.rSum);
int mSum = fmax(fmax(l.mSum, r.mSum), l.rSum + r.lSum);
return (struct Status){lSum, rSum, mSum, iSum};
}
//此函数用于在数组a中寻找以[l,r]为区间的最大子序和
struct Status get(int* a, int l, int r){
if (l == r) {
//递归逐层深入直到区间长度缩小为 1 的时候,则lSum, rSum, mSum, iSum都相等
//即递归结束条件
return (struct Status){a[l], a[l], a[l], a[l]};
}
//我们对[l,r]实行分治操作,分为[l,m] 与[m + 1,r](其中m = (l + r) / 2)
int m = (l + r) >> 1;
struct Status lSub = get(a, l, m);
struct Status rSub = get(a, m + 1, r);
return pushUp(lSub, rSub);
}
int maxSubArray(int* nums, int numsSize) {
return get(nums, 0, numsSize - 1).mSum;
}
标签:pre,numsSize,nums,int,sum,Offer,42,iSum,数组 来源: https://blog.csdn.net/MerryMaking7946/article/details/118853226