力扣上的—53.最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
利用双重for循环来求解每个连续子数组的值;
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
指针 | i j |
指针i代表着最外层的for循环,指针j代表着最内层的for循环;
内层每自加一次利用sum来记录值,并与max(最大值)进行比较,假如sum > max则更新max;
当j自加越界时候(即j已经遍历完了数组里面i到最后一位的所有元素),i++;
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|---|
指针 | i | j |
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
指针 | i j |
sum 置为0,重新开始累加;
一直重复,直到指针i越过数组下标(即i遍历完数组的每一位)结束遍历,返回最大值max;
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|---|
指针 | i |
//数组为a[],数组长度为n,数组下标从0开始
int maxx = a[0];
//maxx初始化为数组第一个元素
for(int i = 0; i < n; i++)
{
sum = 0;
for(int j = i; j < n; j++)
{
sum += a[j];
if(sum > maxx)
maxx = sum;
}
}
虽然力扣的题里面没有要求输出连续数组的下标,但是我们可以在代码中一起判断出来左右下标,即在更新最大值的时候更新子数组的左右下标;
int l = 0, r = 0;
......
if(sum > maxx)
{
maxx = sum;
l = i;
r = j;
}
......
但是在数据范围大于5000的时候O(N2)的算法时间复杂度就足以通过所有代码了,所以我们需要O(N)的算法复杂度。
可以使用递推的想法,在第i个位置上的连续最大和只可能是前i-1的连续最大值+第i个的值或者是从第i个重新开始
dp[i] = max(dp[i-1]+a[i],a[i]);
也可以用贪心理解成为当前i-1项的累加为负数时候,就从第i项开始,因为当前i-1项为负的时候,后面的数在怎么加一个负数都不会比不加负数更高
所以代码如下:
//贪心
#include
#define N 21000
int find(int a[],int n)
{
int sum = a[0];
int maxx = sum;
int left = 0,right = 0;
int l = left;
for(int i = 1; i < n; i++)
{
if(sum >= 0)
sum += a[i];
else
{
sum = a[i];
l = i;
}
if(sum > maxx)
{
maxx = sum;
right = i;
left = l;
}
}
printf("%d %d\n",left,right);
//输出起始点位置,当然不需要的可以不输出
return maxx;
}
int main()
{
int a[N],n;
scanf("%d",&n);
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
int maxx = find(a,n);
printf("%d",maxx);
return 0;
}
//动态规划
#include
#define N 21000
using namespace std;
int find(int a[],int n)
{
int dp[N];
dp[0] = a[0];
int maxx = a[0];
for(int i = 1; i < n; i++)
{
dp[i] = max(dp[i-1] + a[i],a[i]);
if(maxx < dp[i])
{
maxx = dp[i];
}
}
return maxx;
}
int main()
{
int a[N],n;
scanf("%d",&n);
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
int maxx = find(a,n);
printf("%d",maxx);
return 0;
}
int maxSubArray(int* nums, int numsSize){
int sum = nums[0];
int maxx = sum;
for(int i = 1; i < numsSize; i++)
{
if(sum >= 0)
sum += nums[i];
else
sum = nums[i];
if(sum > maxx)
maxx = sum;
}
return maxx;
}
int max(int a,int b)
{
if(a >= b)
return a;
else
return b;
}
int maxSubArray(int* nums, int numsSize){
int maxx = nums[0];
int dp[numsSize];
dp[0] = nums[0];
for(int i = 1; i < numsSize; i++)
{
dp[i] = max(dp[i-1]+nums[i],nums[i]);
if(maxx < dp[i])
maxx = dp[i];
}
return maxx;
}
最后还有一种解法是分治法,即把序列分成两段,要么最大子序和在左边,要么在右边,要么就是在中间被分成了两段,左边一段右边一段;然后在继续分治……