看了若干篇的博客,终于想明白了,尽量用最通俗易懂的方法讲解这个问题。
暴力解决:
时间复杂度O(n^3)
int sum = 0;
for(int i = 0; i < n; ++i)
{
for(int j = i; j < n; ++j)
{
for(int k = 0; k <= j; ++k)
sum += A[k];
if(sum > max)
max = sum;
sum = 0;//注意此处必须置为0,防止重复相加
}
}
return max;
时间复杂度O(n^2)
int sum;
for(int i = 0; i < n; ++i)
{
sum = 0;//这两种方式的区别应该是显而易见的!,不再赘述。
for(int j = i; j < n; ++j)
{
sum += A[j];
if(sum > max)
max = sum;
}
}
分治策略(递归):时间复杂度O(nlogn)
int find_max_sub(vector<int>& vi, int start,int end,int &left,int &right)
{
if(start<=end)
{
int mid=start+(end-start)/2;
int lfv,rhv;
int ll,lr;
int rl,rr;
lfv=find_max_sub(vi,start,mid-1,ll,lr);
rhv=find_max_sub(vi,mid+1,end,rl,rr);
//找到包含vi[mid]的最大子数组
int i=0;
int temp=vi[mid];
int l_index=mid;
int l_value=vi[mid];
for(i = mid - 1; i >= start; i--)
{
l_value += vi[i];
l_index = l_value > temp ? i : l_index;
temp = l_value > temp ? l_value : temp;
}
l_value = temp;
temp=vi[mid];
int r_index=mid;
int r_value=vi[mid];
for(i = mid + 1; i <= end; i++)
{
r_value += vi[i];
r_index = r_value > temp ? i : r_index;
temp = r_value > temp ? r_value : temp;
}
r_value = temp;
temp = l_value + r_value - vi[mid];
return
(lfv < rhv ? (rhv < temp ? (left = l_index, right = r_index, temp) : (left = rl,right = rr, rhv))
: (lfv < temp ? (left = l_index, right = r_index, temp) : (left = ll, right = lr, lfv)));//返回三者中的最大值
}
else
return INT_MIN;
}
第三种方法,时间复杂度O(n);(难点)
假设数组为A[0,...,n-1],包含n个元素;初始化sum=0,从左到右遍历数组,sum=sum+A[i];现在,假设数组中一定会存在j,使得如下两个不等式成立:sum > 0 && sum + A[j] < 0(此处的j为第一次遇到这种情况),到此时为止,令sum=0;按照上述规则把所有的j找到,那么数组就被分为了如下情况:A[1....j1.....j2....j3.....n-1],最大子数组一定处于某个部分之中,不会横跨两个部分,也就是说肯定不会包含下标j(代指j1,j2,j3,....)。假如不存在这样的j,那么可以将数组看做一个整体处理;代码如下,接合代码思考这个问题:
int FIND_MAXIMUN_SUBARRAY(int* A,int n)
{
int sum = 0;
int max = -INF;//INF表示最大的整数
for(int i = 0; i < n; ++i)
{
sum += A[i]; // if(sum < 0)
if(sum < 0) // sum = A[i];
sum = 0; // else sum += A[i];后边的代码能够处理全是负数的情况
if(max < sum)
max = sum;
}
return max;
}