【发布时间】:2013-01-16 07:24:29
【问题描述】:
免责声明:这是一个作业。我不是要求明确的代码,只要求足够的帮助来理解所涉及的算法,以便我可以修复代码中的错误。
好的,所以您可能熟悉最大子数组问题:计算并返回数组中最大的连续整数块。很简单,但这个任务需要我以三种不同的复杂度来完成:O(n^3)、O(n^2) 和 O(n log n)。我已经得到了前两个没有太多麻烦(蛮力),但第三个让我头疼..字面意思。
我理解算法应该如何工作:一个数组被传递给一个函数,该函数递归地将它分成两半,然后比较各个组件以找到每一半的最大子数组。然后,因为最大子数组必须完全位于左半部分或右半部分,或者位于与两者重叠的段中,所以您必须找到与左半部分和右半部分重叠的最大子数组。比较每种情况的最大子数组,最大的将是您的返回值。
我相信我编写的代码可以充分执行该任务,但我的评估似乎是错误的。我一直在尝试联系导师和助教寻求帮助,但我觉得他们中的任何一个都没有取得任何进展。以下是我迄今为止设法编写的代码。如果您发现任何明显的错误,请告诉我。同样,我不是在寻找明确的代码或答案,而是帮助理解我做错了什么。我浏览了这里介绍的所有类似案例,但没有发现任何可以真正帮助我的东西。我也做了很多谷歌搜索以寻求指导,但这也无济于事。无论如何,这是有问题的代码:
int conquer(int arr[], int first, int mid, int last) {
int i = 0;
int maxLeft = 0;
int maxRight = 0;
int temp = 0;
for (i = mid; i >= first; i--) {
temp = temp + arr[i];
if (maxLeft < temp) {
maxLeft = temp;
}
}
temp = 0;
for (i = (mid + 1); i <= last; i++) {
temp = temp + arr[i];
if (maxRight < temp) {
maxRight = temp;
}
}
return (maxLeft + maxRight);
}
int divide(int arr[], int start, int end) {
int i;
int maxSum;
int maxLeftSum;
int maxRightSum;
int maxOverlapSum;
if (start == end) {
return arr[start];
} else {
int first = start;
int mid = (end / 2);
int last = end;
maxSum = 0;
maxLeftSum = 0;
for (i = first; i < mid; i++) {
maxSum = maxSum + arr[i];
if (maxLeftSum < maxSum) {
maxLeftSum = maxSum;
}
}
for (i = (mid + 1); i < last; i++) {
maxSum = maxSum + arr[i];
if (maxRightSum < maxSum) {
maxRightSum = maxSum;
}
}
maxOverlapSum = conquer(arr, first, mid, last);
}
if ((maxLeftSum > maxRightSum) && (maxLeftSum > maxOverlapSum)) {
return maxLeftSum;
} else if ((maxRightSum > maxLeftSum) && (maxRightSum > maxOverlapSum)) {
return maxRightSum;
} else
return maxOverlapSum;
}
编辑:我得到的错误是不正确的结果。我的其他两种算法之间的结果一致且正确,但这个不正确。
编辑#2:这是我的代码的更新版本,精简了一点,我修复了一些问题。它仍然无法正常运行,但应该更接近......
#include <stdio.h>
#include <stdlib.h>
int numarr[] = {22, -27, 38, -34, 49, 40, 13, -44, -13, 28, 46, 7, -26, 42,
29, 0, -6, 35, 23, -37, 10, 12, -2, 18, -12, -49, -10, 37, -5, 17,
6, -11, -22, -17, -50, -40, 44, 14, -41, 19, -15, 45, -23, 48, -1,
-39, -46, 15, 3, -32, -29, -48, -19, 27, -33, -8, 11, 21, -43, 24,
5, 34, -36, -9, 16, -31, -7, -24, -47, -14, -16, -18, 39, -30, 33,
-45, -38, 41, -3, 4, -25, 20, -35, 32, 26, 47, 2, -4, 8, 9, 31, -28,
36, 1, -21, 30, 43, 25, -20, -42};
int length = ((sizeof(numarr))/(sizeof(int)));
int divide(int left, int right) {
int mid, i, temp, mLeft, mRight, mCross = 0;
if (left == right) {
return left;
} else if (left > right) {
return 0;
} else {
mid = (left + right) / 2;
divide(left, mid);
divide(mid + 1, right);
for (i = mid; i >= left; i--) {
temp = temp + numarr[i];
if (mLeft < temp) {
mLeft = temp;
}
}
for (i = mid + 1; i <= right; i++) {
temp = temp + numarr[i];
if (mRight < temp) {
mRight = temp;
}
}
mCross = (mLeft + mRight);
printf("mLeft: %d\n", mLeft);
printf("mRight: %d\n", mRight);
printf("mCross: %d\n", mCross);
return 0;
}
}
int main(int argc, char const *argv[])
{
divide(0, length);
return 0;
}
【问题讨论】:
-
我希望我有时间回答这个问题,但我即将开始一个多小时的通勤时间。我不得不提一下,这是很长时间以来我在 SO 上看到的最好的 presented 家庭作业任务之一。哦,与大多数学生不同,您的代码格式、命名等是专业的。它在没有 cmets 的情况下可读,这说明了很多。祝你好运。
-
您必须执行除法步骤。您当前的实现仅计算最终迭代的重叠和,因此您错过了较小子数组的重叠和。
-
我假设他们为您提供了答案,如果是这样,我很好奇他们声称它是什么。这将有助于了解您的算法何时最终达到所有气缸。
-
我不知道他们是否会,但我会在我弄清楚时告诉你。我几乎可以肯定我现在拥有该算法,因此只需清理我的实现以使其正常工作。不过,我已经接近了!
-
@idigyourpast 我有 223 个答案,但如果来自...显示分区是......挑战 =P
标签: c algorithm recursion divide-and-conquer