434
社区成员
发帖
与我相关
我的任务
分享int maxmerge(int a[], int left, int right)
{
int mid = (left+right)/2;
int s1,s2,sum=0,max=-10000;
if(left == right) return a[left];
s1 = maxmerge(a,left,mid);
s2 = maxmerge(a,mid+1,right); //分解子问题
for(int i=mid;i>=0;i--)
{
sum += a[i];
if(sum > max) max = sum;
}
sum = max; //求解子问题
for(int i=mid+1;i<=right;i++)
{
sum += a[i];
if(sum > max) max = sum; //合并子问题
}
if(max<s1) max = s1;
else if(max<s2) max = s2;
return max;
}
最大值有以下三种情况:
整个序列的字段和与左半部分相同
整个序列的子段和与右半部分相同
整个序列的子段和 在两个部分的中间连接部分
分解子问题:O(1)
求解子问题:拆分子数组分别求得两个长度为n/2的最大子段和,时间复杂度2T(n/2)
合并子问题:O(n)
T(n)=2T(n/2)+O(n)=O(nlogn)
分治法将一个问题划分为数个可以用相同方式求解的子问题,使得子问题的规模简单到可以直接求解,而原问题就是这些子问题的解的合并。
这段代码是一个使用分治策略的函数,旨在找出给定数组中的最大子段和。不过,我有几个点想要提出:
你的注释中,你提到“整个序列的字段和与左半部分相同”,我想这可能是指“整个序列的子段和与左半部分相同”。如果这是你的意图,你可能希望在代码中明确这一点。
你在代码中两次遍历了数组的部分元素来找出最大的子段和。这部分代码可能存在问题。在第一次遍历中,你计算了从mid到0的和,并在和大于max时更新max。然后在第二次遍历中,你再次计算了和,并在和大于max时再次更新max。但是,你应该只在第二次遍历中更新max,因为第二次遍历包括了在第一次遍历中被忽略的元素。
在函数maxmerge的最后一行,你返回的是max而不是maxmerge(a, left, mid)或maxmerge(a, mid+1, right)。这可能是一个错误,因为你可能需要从子数组的最大和中选择最大的一个。
以下是我对你的代码进行的一些修改:
int maxmerge(int a[], int left, int right) {
if(left == right) return a[left]; // if there's only one element, return it
int mid = (left + right) / 2;
int s1 = maxmerge(a, left, mid); // merge the left half
int s2 = maxmerge(a, mid + 1, right); // merge the right half
// merge the two subarrays and find the maximum sum
int sum = 0, max = -10000;
for(int i = mid; i >= 0; i--) { // merge from mid to the start of the array
sum += a[i];
if(sum > max) max = sum;
}
for(int i = mid + 1; i <= right; i++) { // merge from mid+1 to the end of the array
sum += a[i];
if(sum > max) max = sum;
}
return max != -10000 ? max : (s1 > s2 ? s1 : s2); // if max is still the initial value, it means there's no sum greater than -10000, so return the greater between s1 and s2
}
在这个修改后的版本中,我首先合并左半部分和右半部分的子数组,然后合并两个子数组并找出最大的和。最后,如果最大和不在两个子数组中,我就返回两个子数组中的最大值;否则,我返回最大的和。