新手入门的最大子序列和问题,就是一道典型的分治思想算法问题。这里引用浙江大学陈越老师的讲义内容:
分而治之的思想就是将问题一分为二(我觉得其实也就是递归),再在子问题继续分,也就是递归。在这道题中,分完后就是“治”:每两个元素对比取max。不过这里我们需要考虑跨界问题,如上图左边,4-5间元素最大和为6,后续的分析都是一样的。
以下是代码实现,它的时间复杂度是O(NlogN):
public static int maxSum3(int[] nums,int left,int right){
int mid=0,maxLeftSum=0,maxRightSum=0;
int maxLeftBorderSum=0,maxRightBorderSum=0;
/当只有一个元素时
if(left==right){
return Math.max(nums[left], 0);
}
//分
mid=(left+right)/2;
maxLeftSum=maxSum3(nums,left,mid);
maxRightSum=maxSum3(nums,mid+1,right);
//跨界扫描
//向左扫描
int leftBorderSum=0;
for(int i=mid;i>=left;i--){
leftBorderSum+=nums[i];
}
if(leftBorderSum>maxLeftBorderSum){
maxLeftBorderSum=leftBorderSum;
}
//向右扫描
int rightBorderSum=0;
for(int i=mid+1;i<=right;i++){
rightBorderSum+=nums[i];
}
if(rightBorderSum>maxRightBorderSum){
maxRightBorderSum=rightBorderSum;
}
return Math.max(maxLeftSum,Math.max(maxRightSum,maxLeftBorderSum+maxRightBorderSum));
}
这道题陈老师也提供了个更快的解法,代码实现就是:
public static int maxSum4(int [] nums){
int sum=0,maxsum=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i];
if(sum>maxsum){
maxsum=sum;
//如果发现当前子序列和为负,抛弃
}else if(sum<0){
sum=0;
}
}
return maxsum;
}
这个解法也比较好理解,它的时间复杂度是O(N)