1.1 什么是数据结构

1.2 什么是算法

1.3 应用实例:最大子列和问题
给定N个整数的序列 {A_1, A_2, ..., A_N},求最大子列和,即如下函数的最大值:
算法1:暴力求解 T(N)=O(N^3)

算法2:暴力求解,简化了一些 T(N)=O(N^2)

算法3:分而治之 T(N)=O(Nlog(N))
该子列只有这三种可能:①在左边、②在右边、③跨过中间。
假如我有一个函数可以求出长度为K的子列的最大子列和。
那么,就可以用递归的思想,继续划分为更小的单元。
比如求①的时候变成求长度为K/2的子列的最大子列和,调用自身。
递归的终止条件:子列只有一个元素。
递归链条:
在左边、在右边,比较简单。
跨过中间的,比较麻烦。需要同时向两边扫描。

//----------------------------方法3------------------------------//
int Max3( int A, int B, int C )
{ /* 返回3个整数中的最大值 */
//return A > B ? A > C ? A : C : B > C ? B : C;
return ( A > B ? (A > C ? A : C ) : (B > C ? B : C) ); // 加上括号好懂多了
}
int DivideAndConquer( int List[], int left, int right )
{ /* 分治法求List[left]到List[right]的最大子列和 */
int MaxLeftSum, MaxRightSum; /* 存放左右子问题的解 */
int MaxLeftBorderSum, MaxRightBorderSum; /*存放跨分界线的结果*/
int LeftBorderSum, RightBorderSum;
int center, i;
if( left == right ) { /* 递归的终止条件,子列只有1个数字 */
if( List[left] > 0 ) return List[left];
else return 0;
}
/* 下面是"分"的过程 */
/* 找到中分点 */
center = ( left + right ) / 2;
/* 递归求得两边子列的最大和 */
MaxLeftSum = DivideAndConquer( List, left, center );
MaxRightSum = DivideAndConquer( List, center+1, right );
/* 下面求跨分界线的最大子列和 */
MaxLeftBorderSum = 0; LeftBorderSum = 0;
for( i=center; i>=left; i-- ) { /* 从中线向左扫描 */
LeftBorderSum += List[i];
if( LeftBorderSum > MaxLeftBorderSum )
MaxLeftBorderSum = LeftBorderSum;
} /* 左边扫描结束 */
MaxRightBorderSum = 0; RightBorderSum = 0;
for( i=center+1; i<=right; i++ ) { /* 从中线向右扫描 */
RightBorderSum += List[i];
if( RightBorderSum > MaxRightBorderSum )
MaxRightBorderSum = RightBorderSum;
} /* 右边扫描结束 */
/* 下面返回"治"的结果 */
return Max3( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );
}
int MaxSubseqSum3( int List[], int N )
{ /* 保持与前2种算法相同的函数接口 */
return DivideAndConquer( List, 0, N-1 );
}
算法4:T(N)=O(N)

加强版:返回最大子列的起点、终点对应的数字,并处理特殊情况
01-复杂度2 Maximum Subsequence Sum (25分)

#include<stdio.h>
//----------------------------方法4 补充------------------------------//
int MaxStart = 0; //最大子列和的起点
int MaxEnd = 0; //最大子列和的终点
int flag = -1; //-1表示全是负数,0表示有正数,正数表示仅负数和0情况下第一次遇到0的位置
int MaxSubseqSum4p( int A[], int N )
{
int ThisSum = 0, MaxSum = 0;
int ThisStart = 0; // 当前子列的起点
int i;
for( i = 0; i < N; i++ ) {
if(A[i] > 0)
flag = 0; //正常情况,有正数
else if (A[i] == 0 && flag < 0)
{
ThisStart = i+1;
flag = i; //仅负数、0的情况,记录第一次遇到0的位置
}
ThisSum += A[i]; /* 向右累加 */
if( ThisSum > MaxSum )
{
MaxSum = ThisSum; /* 发现更大和则更新当前结果 */
MaxStart = ThisStart;
MaxEnd = i;
}
else if( ThisSum < 0 ) /* 如果当前子列和为负数*/
{
ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之 */
//但是 ThisSum == 0 的情况不能直接抛弃。因为如 1 -1 2 -2,根据要求最大子列是1 -1 2
ThisStart = i+1;
}
}
return MaxSum;
}
//----------------------------main函数------------------------------//
int main()
{
int K = 0, i = 0;
//printf("请输入正整数 K = ");
scanf("%d", &K);
//printf("请输入K个数,用空格分隔:");
int a[K];
for(i=0; i<K; i++){
scanf("%d", &a[i]);
}
printf("%d ", MaxSubseqSum4p(a, K));
if(flag == 0) //正常情况,有正数
printf("%d %d", a[MaxStart], a[MaxEnd]); // 注意是返回起点、终点对应的数字,而不是起点、终点
else if(flag == -1) //全是负数
printf("%d %d", a[0], a[K-1]);
else //仅负数、0
printf("%d %d", a[flag], a[flag]);
}

各种特殊情况,真是锻炼……哈哈哈