您的位置:首页 > 其它

算法学习-零子数组,最大连续子数组

2016-12-05 17:55 197 查看
题目

对于长度为N的数组A,求连续子数组的和最接近0的值。

如:

数组A:1,-2,3,10,-4,7,2,-5

它是所有子数组中,和最接近0的是哪个?

算法流程

申请比A长1的空间sum[-1,0,...,N-1],sum[i]是A的前i项和。定义sum[-1]=0

显然有:A的i到j项和=sum(j)-sum(i-1)

算法思路:

对sum[-1,0,...,N-1]排序,然后计算sum相邻元素的差的绝对值,最小即为所求

在A中任意取两个前缀子数组的和,求差的最小值。

讨论

计算前n项和数组sum和计算sum相邻元素差的时间复杂度,都是O(N),排序的时间复杂度认为是O(N*logN),因此,总时间复杂度:O(NlogN)。

思考:如果需要返回绝对值最小的子数组本身呢?

代码如下

int MinSubarray(const int* a, int size)
{
int* sum = new int[size + 1];
sum[0] = 0;
int i;
for (i = 0; i < size; i++)
{
sum[i + 1] = sum[i] + a[i];
}
sort(sum, sum + size + 1);
int difference = abs(sum[1] - sum[0]);
int result = difference;
for (i = 1; i < size; i++)
{
difference = abs(sum[i + 1] - sum[i]);
result = min(difference, result);
}
delete[] sum;
return result;
}

下面来看一下最大连续子数组的问题

给定一个数组A[0,...,n-1],求A的连续子数组,使得该子数组的和最大。

例如:数组1,-2,3,10,-4,7,2,-5最大子数组:3,10,-4,7,2

分析

记S[i]为以A[i]结尾的数组中和最大的子数组,则:S[i+1]=max(S[i]+A[i+1],A[i+1])

S[0]=A[0]

遍历i:0<=i<=n-1

动态规划:最优子问题

时间复杂度O(n)

代码如下

int MaxSubarray(const int* a, int size)
{
if (!a || (size <= 0))
return 0;

int sum = a[0];  // 当前子串的和
int result = sum;  // 当前找到的最优解
for (int i = 1; i < size; i++)
{
if (sum > 0)
{
sum += a[i];
}
else
{
sum = a[i];
}
result = max(sum, result);
}
return result;
}

求最大子数组还有一种思路如下:

定义:前缀和sum[i]=a[0]+a[1]+...+a[i]则:a[i,j]=sum[j]-sum[i-1](定义p[-1]=0),最大子数组=sum(j)-sum(i-1)

算法过程

求i前缀sum[i]:
遍历i:0<=i<=n-1
sum[i]=sum[i-1]+a[i]

计算以a[j]结尾的子数组的最大值
对于某个j:遍历0<=i<=j,求sum[i]的最小值m
sum[j]-m即为a[j]结尾的数组中最大的子数组的值

统计sum[j]-m的最大值,0<=j<=n-1
1,2,3步都是线性的,因此,时间复杂度O(n)。

如果要求子数组本身,只需要记录一下from和to就可以了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: