题目
在一个有N个元素的数组中,其中每个元素的值可正可负,在该数组中求一个连续子数组,使得该数组的和最大
思路
拿到这个题首先想到的是暴力法,即暴力循环求所有数组的和,因此可以求的该数组的最大值,其时间复杂度为O(N^3)
时间复杂度较高,我们可以用分治法和动态规划来做这道题。其中分治法时间复杂度为O(N*logN),而动态规划为O(N)。
代码
暴力法:
private static void f1(int[] array) {
if (array == null || array.length <= 0) {
return;
}
if (array.length == 1) {
System.out.println(array[0]);
}
int max = array[0];//最大值
int start = 0; //数组的起始下标
int end = 0; //数组的终止下标
for (int i = 0; i < array.length; i++) {
for (int j = i; j < array.length; j++) {
int sum = 0;
for (int k = i; k <= j; k++) {
sum += array[k];
}
if (sum > max) {
max = sum;
start = i;
end = j;
}
}
}
for (int i = start; i <= end; i++) {
System.out.print(array[i] + " ");
}
System.out.println("\n" + max);
}
分治法
private static int f2(int[] array, int start, int end) {
if (start == end) {
return array[start];
}
int mid = (start + end) / 2;
int m1 = f2(array, start, mid); // 最大值在前一半
int m2 = f2(array, mid + 1, end); // 最大值在后一半
int mf = array[mid];
int sum = 0;
for (int i = mid; i >= start; i--) {
sum += array[i];
if (sum > mf) {
mf = sum;
from = i; //子数组的起始下标
}
}
int mb = array[mid + 1];
sum = 0;
for (int i = mid + 1; i <= end; i++) {
sum += array[i];
if (sum > mb) {
mb = sum;
to = i; //子数组的终止下标
}
}
int m3 = mf + mb;
int res = 0;
if (m1 > m2) {
res = m1;
} else {
res = m2;
}
if (res < m3) {
res = m3;
}
return res;
}
动态规划:
// s[k+1] = max ( s[k]+a[k+1], a[k+1] ) 要么继续连续,要么断开
private static int f3(int[] array, int start, int end) {
int max = Integer.MIN_VALUE;
int sum = array[start];
for (int i = start + 1; i < end; i++) {
if (sum < 0) {
from = i;
sum = array[i];
} else {
sum += array[i];
}
if (sum > max) {
max = sum;
to = i;
}
}
return max;
}