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. \]
函数 | 名称 |
---|---|
常量 | |
对数 | |
对数的平方 | |
线性 | |
二次 | |
三次 | |
指数 |
影响程序运行的时间有好多因素:
后两者是我们要关心的.
给定整数
最好能输出和是最大的那个子序列(可能不止一个).
为简单起见, 如果所有整数均为负数, 则最大子序列和定义为 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 }
不妨假设开始时
因此, 运行时间是