最大子序列和详解
在求解最大子序列和时可以使用多种不同的方法 其中对于分治思想:将一个n规模的问题分为2个n/2规模的问题,再将问题的解做简单合并。其中n/2规模的问题可以继续分开处理。对于最大子序列和最大值存在3种情况1在左边2在右边3跨越中间,如果跨越中间将左侧最左部分一直相加到右侧最右部分即可判断。
详细代码如下:
void test(){
// int array[] = {4 , -3, 5, 2, -1, 2, 8, -2, 100};
int array[] = {-4 , -3, 5, 2, -1, 2, 8, -2, -100};
// int array[] = {-4 , -3, 5, 2, -1, 2, 8, -2, -100, 3};
// int array[] = {-4 , -3, 5, 2, -1, 2, 8, -2, -100, 300};
// int array[] = {-1, 2, 3, -3};
// int array[] = {-1, 2};
findSequence(array, sizeof(array)/sizeof(int));
findSequenceOptimize(array, sizeof(array)/sizeof(int));
findSequencePosition(array, sizeof(array)/sizeof(int));
findSequencePositionOptimize(array, sizeof(array)/sizeof(int));
int result = deleaveSequenceSum(array, sizeof(array)/sizeof(int));
NSLog(@"the result is %d", result);
int a = 0;
int b = 0;
result = deleaveSequenceSumRecursionByjeffasd(array, sizeof(array)/sizeof(int), &a, &b);
NSLog(@"the result is %d", result);
}
void findSequence(int arr[], int length){
static int calculateCount = 0;
int maxSum = 0;
for (int i = 0; i < length; i++) {
int sequeueSum = arr[i];
for (int j = i + 1; j < length; j++) {
sequeueSum += arr[j];
if (sequeueSum > maxSum) {
maxSum = sequeueSum;
}
printf("calculate count is %d\n", calculateCount++);
}
}
printf("maxSum is %d\n", maxSum);
}
/** 最优算法 */
void findSequenceOptimize(int arr[], int length){
int maxSum = 0;
int sequeueSum = 0;
for (int i = 0; i < length; i++) {
sequeueSum += arr[i];
if (sequeueSum > maxSum) {
maxSum = sequeueSum;
}else if (sequeueSum < 0){
sequeueSum = 0;//重点是这个 当序列和小于0时将序列和置为0
}
}
printf("maxSum is %d", maxSum);
}
/** 最大子序列和带子序列的位置计算 */
void findSequencePosition(int arr[], int length){
int maxSum = 0;
int start = 0;
int end = 0;
for (int i = 0; i < length; i++) {
int sequeueSum = 0;
for (int j = i; j < length; j++) {
sequeueSum += arr[j];
if (sequeueSum > maxSum) {
maxSum = sequeueSum;
end = j;
start = i;
}
}
}
for (int i = start; i <= end; i++) {
int temp = arr[i];
printf("sequence value position %d is %d\n", i, temp);
}
printf("maxSum is %d\n", maxSum);
}
/** 带位置计算最优算法 */
void findSequencePositionOptimize(int arr[], int length){
int maxSum = 0;
int sequeueSum = 0;
int start = 0;
int end = 0;
BOOL startIsInNext = YES;
for (int i = 0; i < length; i++) {
sequeueSum += arr[i];
if (sequeueSum > maxSum) {
maxSum = sequeueSum;
end = i;
if (startIsInNext == YES) {
start = i;
startIsInNext = NO;
}
}else if (sequeueSum < 0){
sequeueSum = 0;//重点是这个 当序列和小于0时将序列和置为0
if (i != length - 1) {
startIsInNext = YES;
}
}
}
for (int i = start; i <= end; i++) {
int temp = arr[i];
printf("sequence value position %d is %d\n", i, temp);
}
printf("maxSum is %d", maxSum);
}
#define _in
#define _out
#define _inout
int findSequencePositionByDeleave(int arr[], int length, _out int * startP, _out int * endP){
int maxSum = 0;
// *startP = 0;
// *endP = 0;
for (int i = 0; i < length; i++) {
int sequeueSum = 0;
for (int j = i; j < length; j++) {
sequeueSum += arr[j];
if (sequeueSum > maxSum) {
maxSum = sequeueSum;
*endP = j;
*startP = i;
}
}
}
for (int i = *startP; i <= *endP; i++) {
int temp = arr[i];
printf("sequence value position %d is %d\n", i, temp);
}
// //左侧
// int mid = length/2;
//左侧 0-mid
//右侧 mid+1 - length
//1.值全部在左侧
//2.值全部在右侧
//3.值跨越左侧和右侧
printf("maxSum is %d\n", maxSum);
return maxSum;
}
/** 将问题分成两部分再分别处理 伪分治算法 */
int deleaveSequenceSum(_in int arr[], _in int length){
//左侧
int mid = length/2;
int leftStart = 0;
int rightEnd = 0;
int leftSum = 0;
int rightSum = 0;
int tempSum = 0;
int tempLeftStart = 0;
leftSum = findSequencePositionByDeleave(arr, mid, &leftStart, &rightEnd);
rightSum = findSequencePositionByDeleave(&arr[mid], length - (mid), &tempLeftStart, &rightEnd);
rightEnd = rightEnd + mid;
for (int i = leftStart; i <= rightEnd; i++) {
tempSum += arr[i];
printf("sequence value tempSum %d is %d\n", i, tempSum);
}
int leftRightMax = leftSum > rightSum ? leftSum : rightSum;
if (tempSum > leftRightMax ) {
return tempSum;
}else{
return leftRightMax;
}
}
//首先找到问题的最小规模 最小规模的计算要和 非最小规模的计算分开 非最小规模可以将问题拆分成两个或更多个相同或相似的子问题,再把子问题分成更小的子问题 再将多个子问题的和做合并
//分治递归解决问题
int deleaveSequenceSumRecursionByjeffasd(_in int arr[], _in int length, _out int * startP, _out int * endP){
//问题的最小规模 - 当length为2时还可以再次细分
static int calculateCount = 0;
printf("calculate count is %d\n", calculateCount++);
if (length <= 1) {
//起点和重点都是 0
*startP = 0;
*endP = 0;
return arr[0];
}else{
//左侧
int mid = length/2;
int leftStart = 0;
int rightEnd = 0;
int leftStartTemp = 0;
int rightEndTemp = 0;
int leftSum = 0;
int rightSum = 0;
int tempSum = 0;
leftSum = deleaveSequenceSumRecursionByjeffasd(arr, mid, &leftStart, &rightEndTemp);//计算左侧 起点 此处不关心 右侧结束点
rightSum = deleaveSequenceSumRecursionByjeffasd(&arr[mid], length - (mid), &leftStartTemp, &rightEnd);//计算右侧 结束点 此处不关心 左侧起点
leftStartTemp = leftStartTemp + mid;
rightEnd = rightEnd + mid;
for (int i = leftStart; i <= rightEnd; i++) {
tempSum += arr[i];
printf("sequence value tempSum %d is %d\n", i, tempSum);
}
int leftRightMax = leftSum > rightSum ? leftSum : rightSum;
if (tempSum > leftRightMax ) {
*startP = leftStart;
*endP = rightEnd;
return tempSum;
}else{
if (leftSum > rightSum) {
*startP = leftStart;
*endP = rightEndTemp;
}else{
*startP = leftStartTemp;
*endP = rightEnd;
}
return leftRightMax;
}
}
}