算法学习-零子数组,最大连续子数组
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)。
思考:如果需要返回绝对值最小的子数组本身呢?
代码如下
下面来看一下最大连续子数组的问题
给定一个数组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)
代码如下
求最大子数组还有一种思路如下:
定义:前缀和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就可以了
对于长度为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就可以了
相关文章推荐
- 算法学习---求数组中的最大数
- 算法学习笔记----最大子数组问题
- 算法学习--3 最大子数组和以及进阶问题
- 每天学习一算法系列(5)(已知两个数组,数组里的元素有正有负,但是都是按照从小到大已经排好序,要求用尽可能小的时间复杂度编写一算法求出两个数组的最大交集)
- 算法学习-最大连续子数组
- 算法学习之路:分治策略-最大子数组-java实现
- 算法学习-连续子数组求和最大值
- 算法学习二----求子数组的最大和
- 算法学习-连续子数组求和最大值
- 算法学习-数组的最大间隔
- 【算法导论学习笔记】最大子数组问题
- 算法学习-连续子数组求和最大值
- 【算法学习】最大子数组问题的分治法求解
- 【算法导论学习-007】最大子数组和问题(Maximum subarray problem)
- 每天学习一算法系列(5)(已知两个数组,数组里的元素有正有负,但是都是按照从小到大已经排好序,要求用尽可能小的时间复杂度编写一算法求出两个数组的最大交集)
- [算法题] 求数组的子数组之和的最大值
- 三种算法求解一个数组的子数组最大和
- 数组中子序列最大和算法
- 算法讨论(二)---求子数组的最大和