This slide is based on Mark Allen Weiss's book.
中译本是《数据结构与算法分析 C++ 描述》张怀勇等译
注意这里的定义可能与数学上的有所不同.
如果存在正常数 $c$ 和 $n_0$, 使得当 $N\geq n_0$ 时, 有 $f(N)\leq cg(N)$, 则记为
\[ \lim_{N\rightarrow\infty}\frac{f(N)}{g(N)}\leq c,\quad c>0. \]
如果存在正常数 $c$ 和 $n_0$, 使得当 $N\geq n_0$ 时, 有 $f(N)\geq cg(N)$, 则记为
\[ \lim_{N\rightarrow\infty}\frac{f(N)}{g(N)}\geq c,\quad c>0. \]
如果存在正常数 $c_1$ 和 $c_2$, 以及 $n_0$, 使得当 $N\geq n_0$ 时, 有 $c_1 g(N)\leq f(N)\leq c_2 g(N)$, 则记为
即 $f(N)=\Theta(g(N))$ 当且仅当 $f(N)=O(g(N))$ 且 $f(N)=\Omega(g(N))$.
\[ \lim_{N\rightarrow\infty}\frac{f(N)}{g(N)}= c,\quad c>0. \]
如果 $f(N)=O(g(N))$, 但是 $f(N)\neq\Theta(g(N))$, 则记为
\[ \lim_{N\rightarrow\infty}\frac{f(N)}{g(N)}=0. \]
在有序数组a中查找元素x. 如果存在, 就返回元素x的位置, 否则返回-1
templateint binarySearch(T a[], int n, const T& x) { int left=0; int right=n-1; while(left<=right) { int middle=(left+right)/2; if(x==a[middle]) return middle; if(x>a[middle]) left=middle+1; else right=middle-1; } return -1; }
| 函数 | 名称 |
|---|---|
| 常量 | |
| 对数 | |
| 对数的平方 | |
| 线性 | |
| 二次 | |
| 三次 | |
| 指数 |
影响程序运行的时间有好多因素:
后两者是我们要关心的.
给定整数
最好能输出和是最大的那个子序列(可能不止一个).
为简单起见, 如果所有整数均为负数, 则最大子序列和定义为 0.
/**
* Cubic maximum contiguous subsequence sum algorithm.
* O(N^3)
* Time: 1.747s
*/
int maxSubSum1( const vector<int> & a )
{
int maxSum = 0;
for( int i = 0; i < a.size( ); i++ )
{
for( int j = i; j < a.size( ); j++ )
{
int thisSum = 0;
for( int k = i; k <= j; k++ )
thisSum += a[ k ];
if( thisSum > maxSum )
maxSum = thisSum;
}
}
return maxSum;
}
算法一中最里层的
/**
* Quadratic maximum contiguous subsequence sum algorithm.
* O(N^2)
*/
int maxSubSum2( const vector<int> & a )
{
int maxSum = 0;
for( int i = 0; i < a.size( ); i++ )
{
int thisSum = 0;
for( int j = i; j < a.size( ); j++ )
{
thisSum += a[ j ];
if( thisSum > maxSum )
maxSum = thisSum;
}
}
return maxSum;
}
算法三使用了递归的思想.
/**
* Recursive maximum contiguous subsequence sum algorithm.
* Finds maximum sum in subarray spanning a[left..right].
* Does not attempt to maintain actual best sequence.
*/
int maxSumRec( const vector<int> & a, int left, int right )
{
if( left == right ) // Base case
if( a[ left ] > 0 )
return a[ left ];
else
return 0;
int center = ( left + right ) / 2;
int maxLeftSum = maxSumRec( a, left, center );
int maxRightSum = maxSumRec( a, center + 1, right );
int maxLeftBorderSum = 0, leftBorderSum = 0;
for( int i = center; i >= left; i-- )
{
leftBorderSum += a[ i ];
if( leftBorderSum > maxLeftBorderSum )
maxLeftBorderSum = leftBorderSum;
}
int maxRightBorderSum = 0, rightBorderSum = 0;
for( int j = center + 1; j <= right; j++ )
{
rightBorderSum += a[ j ];
if( rightBorderSum > maxRightBorderSum )
maxRightBorderSum = rightBorderSum;
}
return max3( maxLeftSum, maxRightSum,
maxLeftBorderSum + maxRightBorderSum );
}
/**
* Driver for divide-and-conquer maximum contiguous
* subsequence sum algorithm.
*/
int maxSubSum3( const vector<int> & a )
{
return maxSumRec( a, 0, a.size( ) - 1 );
}
\[ \begin{cases} T(1)=1\\ T(N)=2T(N/2)+O(N) \end{cases} \]
使用数学归纳法可以证明,
/**
* Linear-time maximum contiguous subsequence sum algorithm.
*/
int maxSubSum4( const vector<int> & a )
{
int maxSum = 0, thisSum = 0;
for( int j = 0; j < a.size( ); j++ )
{
thisSum += a[ j ];
if( thisSum > maxSum )
maxSum = thisSum;
else if( thisSum < 0 )
thisSum = 0;
}
return maxSum;
}
| vector | -2 | 11 | -4 | 13 | -5 | -2 |
|---|---|---|---|---|---|---|
| thisSum | -2$\rightarrow$0 | 11 | 7 | 20 | 15 | 13 |
| maxSum | 0 | 11 | 11 | 20 | 20 | 20 |
仅需常量空间并以线性时间运行的联机算法几乎是完美的算法.
如果我们要求输出达到最大和的连续子序列, 请完善上面的程序.
改进此程序, 要求对于所有数是负数时也能找出最大子序列.
给定一个整数
/**
* Performs the standard binary search using two comparisons per level.
* Returns index where item is found or -1 if not found.
*/
template <typename Comparable>
int binarySearch( const vector<Comparable> & a, const Comparable & x )
{
int low = 0, high = a.size( ) - 1;
while( low <= high )
{
int mid = ( low + high ) / 2;
if( a[ mid ] < x )
low = mid + 1;
else if( a[ mid ] > x )
high = mid - 1;
else
return mid; // Found
}
return NOT_FOUND; // NOT_FOUND is defined as -1
}
不妨假设开始时
因此, 运行时间是