时间复杂度
定义
衡量一个算法的快慢,一定要考虑数据规模的大小。所谓数据规模,一般指输入的数字个数、输入中给出的图的点数与边数等等。一般来说,数据规模越大,算法的用时就越长。而在算法竞赛中,我们衡量一个算法的效率时,最重要的不是看它在某个数据规模下的用时,而是看它的用时随数据规模而增长的趋势,即 时间复杂度。
——OI Wiki
在算法中,使用时间复杂度来衡量程序运行时间的多少。每条语句执行的次数称为该语句的频度,整段代码的总执行次数则称为整段代码的频度。在算法竞赛中,由于输入可以在给定的数据范围内任意给定,我们为保证算法能够通过某个数据范围内的任何数据,一般考虑最坏时间复杂度。
下面,我将用更通俗易懂的语言,解释时间复杂度。
分析
在推导的时候,我们应该采用无限大的思想来简化大 \(O\) 表达式,具体如下:
1.用常数 \(1\) 代替运行时间中的所有加法的常数。无论常数是多少都使用 \(1\) 替换。因为执行函数和问题规模 \(n\) 的大小无关,它是执行时间恒定的,像时间复杂度为\(O(1)\) 的又被称作常数阶。如:执行 \(100\) 次 \(1 \to n\) 的循环,这份代码的时间复杂度为 \(O(n)\) 而并非 \(O(100n)\)。
2.如果最高阶项存在且系数不为 \(1\),则去除掉与这个项相乘的系数,例如 \(O(2n^2)\) 系数为 \(2\),直接简化为 \(O(n^2)\)。
3.如果表达式有多项含有无限大变量的式子,只保留一个拥有指数最高的变量的式子。如 \(O(2n^2+2n)\) 应简化为 \(O(n^2)\)。
经过上面三个步骤推到出来的结果就是算法对应的大 \(O\) 阶。
注意,在遇到类似于 \(O(2n+m)\) 的时间复杂度时,由于 \(n\) 和 \(m\) 之间没有联系,所以这份代码的时间复杂度应是 \(O(n+m)\)。在遇到类似于 \(O(n^2+nq)\) 的时间复杂度时,由于我们无法确定 \(n^2\) 和 \(nq\) 的大小(\(n\) 和 \(q\) 的大小不确定),因此这份代码的时间复杂度依然是 \(O(n^2+nq)\)。
举例:
-
\(O(12)\to O(1)\)
-
\(O(2n+3)\to O(n)\)
-
\(O(3n^2+2n+1)\to O(n^2)\)
-
\(O(5\log_2 n+20)\to O(\log n)\)
-
\(O(2n+3n\log_2 n+19)\to O(n\log n)\)
-
\(O(6n^3+2n^2+3n+4)\to O(n^3)\)
-
\(O(2^n+n^4)\to O(2^n)\)
Another
哪些数是常数?
我们曾提到,“用常数 \(1\) 代替运行时间中的所有加法的常数”,那么,什么是常数呢?
我们一个例子看起。
const int n=114514;
for (int i=1;i<=n;i++){
cout<<"hello world\n";
}
代码中,\(MAXN\) 虽然是一个变量,但是它的值是固定的,所以它不被看做输入数据规模,所以代码的时间复杂度是 \(O(1)\) 而不是 \(O(n)\)。
进行时间复杂度计算时,哪些变量被视作输入规模是很重要的,而所有和输入规模无关的量都被视作常量,计算复杂度时可当作 \(1\) 来处理。
标签:代码,浅谈,复杂度,算法,时间,2n,常数 From: https://www.cnblogs.com/shimingxin1007/p/18306144