1.3 应用实例:最大子列和问题
1.3.1应用实例-算法1&2
给定N个整数的序列{
A
1
,
A
2
.
.
.
,
A
N
A_1,A_2...,A_N
A1?,A2?...,AN?},求函数
f
(
i
,
j
)
=
m
a
x
(
0
,
∑
i
=
1
n
A
k
)
f(i,j)=max(0,\displaystyle\sum_{i=1}^{n} A_k)
f(i,j)=max(0,i=1∑n?Ak?)的最大值
int MaxSubseqSum1(int A[],int N){
int ThisSum,MaxSum=0;
int i,j,k;
for(i=0;i<N;i++){
for(j=i;j<N;j++){
ThisSum=0;
for(k=i;k<=j;k++){
ThisSum+=A[k];
}
if(ThisSum>MaxSum)
MaxSum=ThisSum;
}
}
return MaxSum;
}
时间复杂度
T
(
N
)
=
O
(
N
3
)
T(N)=O(N^3)
T(N)=O(N3) 在K循环中浪费了大量的时间,当i不变,j++时,完全没必要从头算起,只需在已算出的ThisSum后再+j即可,故改进为算法2
int MaxSubseqSum1(int A[],int N){
int ThisSum=0,MaxSum=0;
int i,j,k;
for(i=0;i<N;i++){
for(j=i;j<N;j++){
ThisSum+=A[j];
if(ThisSum>MaxSum)
MaxSum=ThisSum;
}
}
return MaxSum;
}
时间复杂度
T
(
N
)
=
O
(
N
2
)
T(N)=O(N^2)
T(N)=O(N2) 一般
O
(
N
2
)
O(N^2)
O(N2)的复杂度,通过二分方法,都可以降到
n
l
o
g
n
nlogn
nlogn,故改进为算法3(分而治之)
1.3.2应用实例-算法3:分而治之
- 算法3
递归的思想
- 把数组从中间一分为二,然后递归地去分别找出左右两边的最大子列和。
- 考虑跨越边界的最大子列和,即从中间开始,往左边扫描,然后往右边扫描
- 返回这三个结果中的最大值。
整个的时间复杂度
T
(
N
)
T(N)
T(N),分成两半后,左右两边规模减半,即两边的时间复杂度都为
T
(
N
/
2
)
T(N/2)
T(N/2)。中间的向左向右每个元素都扫描一次,所以中间的复杂度是N的一个常数倍
O
(
N
)
O(N)
O(N) 故得到: ???
T
(
N
)
=
2
T
(
N
/
2
)
+
c
N
,
??
T
(
1
)
=
O
(
1
)
T(N)=2T(N/2)+cN, \ \ T(1)=O(1)
T(N)=2T(N/2)+cN,??T(1)=O(1) ??? ???? 将N替换成N/2,再将
T
(
N
/
2
)
T(N/2)
T(N/2)代入上式得: ??? ????
T
(
N
)
=
2
[
2
?
T
(
N
/
2
2
)
+
c
N
/
2
]
+
c
N
T(N)=2[2\ T(N/2^2)+cN/2]+cN
T(N)=2[2?T(N/22)+cN/2]+cN ? ??????? ????
=
2
2
?
T
(
N
/
2
2
)
+
2
c
N
=2^2\ T(N/2^2)+2cN
=22?T(N/22)+2cN ? ??????? ????
=
2
k
O
(
1
)
+
c
k
N
=2^kO(1)+ckN
=2kO(1)+ckN? 其中
N
/
2
K
=
1
N/2^K=1
N/2K=1 这一步为展开直到T()里面的数到1为止,展开了k步后得到上面这个式子,其中
k
=
log
?
2
N
k=\log_2^N
k=log2N?,两项的复杂度分别为
O
(
N
)
,
O
(
N
l
o
g
N
)
O(N),O(N logN)
O(N),O(NlogN),两个复杂度相加取大的那个,故: ??? ????
T
(
N
)
=
O
(
N
l
o
g
N
)
T(N)=O(NlogN)
T(N)=O(NlogN)
int Max(int A, int B, int C)
{
if (A > B) {
if (A > C)
return A;
else
return C;
}
else if (B > C)
return B;
else return C;
}
int DivideAndConquer(int List[], int left, int right) {
int MaxLeftSum, MaxRightSum;
int MaxLeftBoardSum, MaxRightBoardSum;
int LeftBoardSum, RightBoardSum;
int center,i;
if (left == right) {
if (List[left] > 0)
return List[left];
else
return 0;
}
center = (right + left) / 2;
MaxLeftSum = DivideAndConquer(List, left, center);
MaxRightSum= DivideAndConquer(List, center+1, right);
MaxLeftBoardSum = 0;
LeftBoardSum = 0;
for (i = center;i >= left; i--)
LeftBoardSum += List[i];
if (LeftBoardSum > MaxLeftBoardSum)
MaxLeftBoardSum = LeftBoardSum;
MaxRightBoardSum = 0;
RightBoardSum = 0;
for (i = center + 1; i <= right; i++)
RightBoardSum += List[i];
if (RightBoardSum > MaxRightBoardSum)
MaxRightBoardSum = RightBoardSum;
return Max(MaxLeftSum, MaxRightSum, MaxRightBoardSum + MaxLeftBoardSum);
}
int MaxSubseqSum3(int A[], int N)
{
return DivideAndConquer(A, 0, N-1);
}
算法3的代码从博主CrownP的文章中学习得到
1.3.3应用实例-算法4:分而治之
int MaxSubsquSum4(int A[],int N){
int ThisSum=0,MaxSum=0;
for(int i=0;i<N;i++){
ThisSum+=A[i];
if(ThisSum>MaxSum){
MaxSum=ThisSum;
}
else if(ThisSum<0){
ThisSum=0;
}
}
return MaxSum;
}
T
(
N
)
=
O
(
N
)
T(N)=O(N)
T(N)=O(N) “在线”的意思使指每输入一个数据就进行计时处理,在任何一个地方中止输入,算法都能正确给出当前的解。
|