package com.lihe.test.collection;
import java.util.Scanner;
public class MaxSequenceSum {
/**
* @author limingyu
* 连续子序列最大和问题:给定(可能是负的)整数序列A1,A2,...An,寻找使的值最大的序列。
* 如果所有的整数都是负的,那么连续子序列的最大和是零。要求算法复杂度为O(N^2)
* 例如输入{-2,11,-4,13,-5,2}答案为20
* 输入{1,-3,4,-2,-1,6}答案是7
*/
public static void main(String[] args) {
int[] arr = new int[]{-2,11,-4,13,-5,2};
System.out.println(maxSequence(arr));
// int[] arr = new int[]{-2,11,-4,-13,-5,2};
// System.out.println("maxSequence1:" + maxSequence1(arr));
}
public static int maxSequence(int[] arr) {
int maxSum = 0;
for (int i = 0; i < arr.length; i++) {
int sum = 0;
for (int j = i; j < arr.length; j++) {
sum += arr[j];
if(sum > maxSum){ //每次求和都進行比較
maxSum = sum;
}
}
}
return maxSum;
}
/**
* 从左到右记录当前子序列的和sum,开始位置为seqStart,结束位置为seqEnd。
* 若currentSum不断增加,那么最大子序列的和maxSum也不断增加(不断更新maxSum,start,end)。
* 如果往前扫描中遇到负数,那么当前子序列的和将会减小。此时currentSum 将会小于maxSum,当然maxSum也就不更新。
* 如果currentSum降到0时,说明前面已经扫描的那一段就可以抛弃了,这时将currentSum置为0,并且seqStart为下一个位置。
* 然后,currentSum将从后面开始将这个子段进行分析,若有比当前maxSum大的子段,继续更新maxSum。这样一趟扫描结果也就出来了。
* 要求算法复杂度为O(N)
*/
public static int maxSequence1(int[] arr){
int maxSum = 0;
int currentSum = 0;
int seqStart = 0;//最大和子序列起始位置
int seqEnd = 0;//最大和子序列结束位置
for(int i = 0,j = 0; j < arr.length; j ++){
currentSum += arr[j];
if(currentSum > maxSum){
maxSum = currentSum;
seqStart = i;
seqEnd = j;
}
/**
* 定理:设Ai,j是满足Si,j<0的任意子序列,如果p>j,那么Ai,q不是最大连续子序列
* 如果一个子序列的和是负的,则它不可能是最大连续子序列的一部分,因为我们可以通过不包含他来得
* 一个更大的连续子序列。或所有与最大连续子序列相邻的连续子序列一定有负的(或0)和(否则会包含他们)
*/
else if(currentSum <= 0){
//当检测到一个负的子序列时,可以让i直接增加到j+1,抛弃掉之前的负子序列,重新开始。
i = j + 1;
currentSum = 0;
}
}
System.out.println("start :" + seqStart + " end : "+ seqEnd);
return maxSum;
}
}
import java.util.Scanner;
public class MaxSequenceSum {
/**
* @author limingyu
* 连续子序列最大和问题:给定(可能是负的)整数序列A1,A2,...An,寻找使的值最大的序列。
* 如果所有的整数都是负的,那么连续子序列的最大和是零。要求算法复杂度为O(N^2)
* 例如输入{-2,11,-4,13,-5,2}答案为20
* 输入{1,-3,4,-2,-1,6}答案是7
*/
public static void main(String[] args) {
int[] arr = new int[]{-2,11,-4,13,-5,2};
System.out.println(maxSequence(arr));
// int[] arr = new int[]{-2,11,-4,-13,-5,2};
// System.out.println("maxSequence1:" + maxSequence1(arr));
}
public static int maxSequence(int[] arr) {
int maxSum = 0;
for (int i = 0; i < arr.length; i++) {
int sum = 0;
for (int j = i; j < arr.length; j++) {
sum += arr[j];
if(sum > maxSum){ //每次求和都進行比較
maxSum = sum;
}
}
}
return maxSum;
}
/**
* 从左到右记录当前子序列的和sum,开始位置为seqStart,结束位置为seqEnd。
* 若currentSum不断增加,那么最大子序列的和maxSum也不断增加(不断更新maxSum,start,end)。
* 如果往前扫描中遇到负数,那么当前子序列的和将会减小。此时currentSum 将会小于maxSum,当然maxSum也就不更新。
* 如果currentSum降到0时,说明前面已经扫描的那一段就可以抛弃了,这时将currentSum置为0,并且seqStart为下一个位置。
* 然后,currentSum将从后面开始将这个子段进行分析,若有比当前maxSum大的子段,继续更新maxSum。这样一趟扫描结果也就出来了。
* 要求算法复杂度为O(N)
*/
public static int maxSequence1(int[] arr){
int maxSum = 0;
int currentSum = 0;
int seqStart = 0;//最大和子序列起始位置
int seqEnd = 0;//最大和子序列结束位置
for(int i = 0,j = 0; j < arr.length; j ++){
currentSum += arr[j];
if(currentSum > maxSum){
maxSum = currentSum;
seqStart = i;
seqEnd = j;
}
/**
* 定理:设Ai,j是满足Si,j<0的任意子序列,如果p>j,那么Ai,q不是最大连续子序列
* 如果一个子序列的和是负的,则它不可能是最大连续子序列的一部分,因为我们可以通过不包含他来得
* 一个更大的连续子序列。或所有与最大连续子序列相邻的连续子序列一定有负的(或0)和(否则会包含他们)
*/
else if(currentSum <= 0){
//当检测到一个负的子序列时,可以让i直接增加到j+1,抛弃掉之前的负子序列,重新开始。
i = j + 1;
currentSum = 0;
}
}
System.out.println("start :" + seqStart + " end : "+ seqEnd);
return maxSum;
}
}