- 时间复杂度:
- 大O记号:如果存在正常数c和c0 使得当N>=n0时T(N)<=cf(N),则记为 T(N) = O(f(N))
在大O记号中比较的其实是“相对增长率”,其实也就是求导后的比较。对于具体的数值是没有意义。比如:某个N0使得f(N0)<g(N0)是没有意义的。
当T(N) = O(f(N))时,f(N)是T(N)的一个“上界”。
几个结论:
结论一:如果T1(N) = O(f(N))且T2(N) = O(g(N)),那么
a) T1(N) + T2(N) = O(f(N) + g(N)); 或者写成max( O(f(N)) , O(g(N)) ).
b) T1(N) * T2(N) = O(f(N) * g(N));
结论二:对于任意常数k,logkN = O(N),说明对数增长的很慢。
- 问题一:最大子序列和问题:
问题描述:给定(包括负数)整数A1,A2,A3 ... AN, 求∑jk=iAk 的最大值。
例子:对于 -2 11 -4 13 -5 -2答案为20
解法1)
直接枚举所有子序列:
public static int maxSubSum(int[] a){
int maxSum = 0;
for(int i = 0; i < a.length; i++){
int thisSum = 0;
for(int j = i; j < a.length; j++){
thisSum += a[j];
if(thisSum > maxSum){
maxSum = thisSum;
}
}
}
return maxSum;
}
时间复杂度 O(N2)
解法二)
分治法:
像一般的分治法一样,分为Divide-conquer-combine几个阶段。
具体为
a) 以中点将序列分为两段 (Divide)
b) 递归求两段的最大子序列
c) 求以中点为轴向两边蔓延的最大子序列,并和b)求的两个值比较,return其中的最大值。
public static int maxSumRec(int[] a, int left, int rigth){
if(left == right){
if(a[left] > 0)
return a[left];
else
return 0;
}
int center = (left + right) / 2; //divide
int maxLeftSum = maxSumRec(a, left, center); //sub problem
int maxRightSum = maxSumRec(a, center + 1, right); //sub problem
int maxLeftBorderSum = 0;
int leftBorderSum = 0;
for(int i = center; j >= left; i--){ //combine
leftBorderSum += a[i];
if(leftBorderSum > maxLeftBorderSum){
maxLeftBorderSum = leftBorderSum;
}
}
int maxRightBorderSum = 0;
int rightBorderSum = 0;
for(int i = center + 1; i <= right; i++){ //combine
rightBorderSum += a[i];
if(rightBorderSum > maxRightBorderSum){
maxRightBorderSum = rightBorderSum;
}
}
if(maxLeftSum < maxRightSum){
maxLeftSum = maxRightSum;
}
if(maxLeftSum < maxLeftBorderSum + maxRightBorderSum){ //combine
maxLeftSum = maxLeftBorderSum + maxRightBorderSum;
}
return maxLeftSum;
}
public static int maxSubSum(int[] a){
return maxSumRec(a, 0, a.length - 1);
}
时间复杂度为O(nlogn)
解法三)
此题有一种线性时间的解法,而且只需要一次扫描即可得到答案,即所谓“联机算法”(on-line algorithm)
public static int maxSubSum(int[] a){
int maxSum = 0 , thisSum = 0;
for(int j = 0; j < a.length; j++){
thisSum += a[j];
if(thisSum > maxSum)
maxSum = thisSum;
else if(thisSum < 0)
thisSum = 0; //这里还是很有技巧
}
return maxSum;
}