求解数列的最大子列和问题,显然我们可以穷举所有长度的子列然后一一比较大小来求得。但空间复杂度太大为n3。现在我们来学习一种新的解决方法。
我们以一个任意子列为例子:0,-2,6,1,-4,3,-12,17,-6;相比较于穷举比较,这个方法只需要遍历一遍。
第一步:0,对后续子列大小无影响,存入,不保留。(此处考虑当子列最短时的最大值)
第二步:-2,对后续子列减小,与上一次存入0比较,小于0,不存入,不保留。
第三步:6,对后续子列增大,与上一次存入0比较,大于0,存入6,保留6并暂定为最大子列起点。
第四步:1,对后续子列增大,与上一次存入6比较,(此处为累加为7)大于6,保留7存入7。
第五步:-4,对后续子列减小,与上一次存入7比较,(此处为累加为3)小于7,保留3但不存入。
第六步:3,对后续子列增大,与上一次存入7比较,(此处为累加为6)小于7,保留6但不存入。
第七步:-12.对后续子列减小,与上一次存入7比较,(此处为累加为-6)小于7,小于0,不保留不存入。
第八步:17 对后续子列增大,与上一次存入7比较,(因为第七步累加结果小于0了,未保留所以这一步并没有累加)大于7,保留并存入且更新最大子列起点。
第九步:-6 对后续子列减小,与上一次存入17比较,(此处累加为11)小于17,保留但不存入。
到这里,整个数列已经遍历一边且得出了最大子列和为17。
#include <stdio.h>
int maxSubArraySum(int arr[], int n) {
int max_so_far = arr[0];
int max_ending_here = arr[0];
for (int i = 1; i < n; i++) {
max_ending_here = (max_ending_here > 0) ? max_ending_here + arr[i] : arr[i];
if (max_ending_here > max_so_far) {
max_so_far = max_ending_here;
}
}
return max_so_far;
}
int main() {
int n;
printf("请输入数列的长度: ");
scanf("%d", &n);
int arr[n]; // 动态分配数组
printf("请输入数列的元素 (用空格分隔): ");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int max_sum = maxSubArraySum(arr, n);
printf("最大子列和为: %d\n", max_sum);
return 0;
}
import java.util.Scanner;
public class MaxSubArraySum {
public static int maxSubArraySum(int[] arr) {
int maxSoFar = arr[0]; // 初始化最大子列和
int maxEndingHere = arr[0]; // 以当前元素结尾的子列和
for (int i = 1; i < arr.length; i++) {
// 计算到当前元素的最大子列和
maxEndingHere = Math.max(arr[i], maxEndingHere + arr[i]);
// 更新全局最大值
maxSoFar = Math.max(maxSoFar, maxEndingHere);
}
return maxSoFar;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数列的长度: ");
int n = scanner.nextInt();
int[] arr = new int[n];
System.out.println("请输入数列的元素 (用空格分隔): ");
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
int maxSum = maxSubArraySum(arr);
System.out.println("最大子列和为: " + maxSum);
scanner.close();
}
}