目录
1 暴力方法
把所有子列和都求出来
public class Demo07 {
public static void method(int[] a) {
int max = Integer.MIN_VALUE;
int begin = -1;
int end = -1;
int len = a.length;
int sum = 0;
for (int i = 0; i < len; i++) {// 子数列的开头
for (int j = i; j < len; j++) {// 子数列的结尾
sum = 0;
for (int k = i; k <= j; k++) {// 计算子数列的和
sum += a[k];
}
if (sum > max) {
max = sum;
begin = i;
end = j;
}
}
}
System.out.println("最大子列和为:" + max + ", 子列开始序号为:" + begin + ", 子列结束序号为:" + end);
}
public static void main(String[] args) {
int[] a = { 1, -5, -9, 7, -5, 4, 3, -8, 5 };
method(a);
}
}
运行结果:
最大子列和为:9, 子列开始序号为:3, 子列结束序号为:6
2 第一种方法的改进:重复利用已经计算的子数组和
public static void method(int[] a) {
int max = Integer.MIN_VALUE;
int begin = -1;
int end = -1;
int len = a.length;
int sum = 0;
for (int i = 0; i < len; i++) {// 子数列的开头
sum = 0;
for (int j = i; j < len; j++) {// 子数列的结尾
sum += a[j];// 从i加到j,下一次循环的时候,利用了上一次循环的和
if (sum > max) {
max = sum;
begin = i;
end = j;
}
}
}
System.out.println("最大子列和为:" + max + ", 子列开始序号为:" + begin + ", 子列结束序号为:" + end);
}
3 动态规划方法【创建了另外两个数列】
转化为动态规划方法解题
具备动态规划的两个特征:具有规模;有递推公式。
具体说明:
对于序号为i的元素来说,前i+1个元素的子序列最大和设为all[i]
设包含i在内的子序列最大和为end[i]
a[i]怎么求解呢?是下面两种情况中大的那个:
- 包含i号元素,即为end[i]。怎么求解呢分为两种情况,选择大的那个:不包含i-1,则为a[i];包含i-1,则为end[i-1] + arr[i]
- 不包含i号元素,就为all[i-1]
代码展示如下:
public static void method(int[] a) {
int n = a.length;
int[] end = new int[n];
int[] all = new int[n];
end[0] = all[0] = a[0];
for (int i = 1; i < n; i++) {
end[i] = a[i] > (end[i - 1] + a[i]) ? a[i] : (end[i - 1] + a[i]);
all[i] = all[i - 1] > end[i] ? all[i - 1] : end[i];
}
System.out.println("最大子列和为:" + all[n - 1]);// 结果应该是9
}
public static void main(String[] args) {
int[] a = { 1, -5, -9, 7, -5, 4, 3, -8, 5 };
method(a);
}
4 优化的动态规划方法【用两个变量来储存end和all】
我们发现就用了i-1的数据,那么我们没有必要新建两个数组来储存end和all的值,用两个int变量来储存就行了。
public static void method(int[] a) {
int n = a.length;
int end = a[0];
int all = a[0];
for (int i = 1; i < n; i++) {
end = a[i] > (end + a[i]) ? a[i] : (end + a[i]);
all = all > end ? all : end;
}
System.out.println("最大子列和为:" + all);// 结果应该是9
}
5 最后一种方法,还能标出子序列的位置【不储存all的值,如果有大的end就更新all】
方法3和方法4中,end[i]=man{a[i], end[i-1]+a[i]}
可以看出,如果end[i-1]的值如果是正数,end[i] = end[i-1] + a[i];否则就为a[i]
对于下面的代码来说:
如果subSum为负,我们,更新subStart为i,subSum为a[i]
否则,我们更新subSum的值为subSum + a[i]
如果subSum大于max则更新max的值,更新开始,结束的序号值
代码如下:
public static int begin = 0;
public static int end = 0;
public static int method(int[] a) {
int max = Integer.MIN_VALUE;
int subSum = a[0];
int subStart = 0;
for (int i = 1; i < a.length; i++) {
if (subSum < 0) {
subStart = i;
subSum = a[i];
} else {
subSum += a[i];
}
if (subSum > max) {
max = subSum;
begin = subStart;
end = i;
}
}
return max;
}
public static void main(String[] args) {
int[] a = { 1, -5, -9, 7, -5, 4, 3, -8, 5 };
System.out.println(method(a));// 9
System.out.println(begin);// 3
System.out.println(end);// 6
}
本文介绍了暴力求解、动态规划优化的方法来寻找数组的最大子数列和,详细阐述了动态规划的思路,包括如何使用两个变量替代数组以节省空间,并能标识出最大子序列的位置。

3047

被折叠的 条评论
为什么被折叠?



