时空复杂度的优化——数学
在解决各种算法问题时,我们常常以O()来表示这个算法的时间复杂度和空间复杂度随着数据规模大小的增长而增长的速率。通常,1s时间内可解出来的时间复杂度与数据规模的关系如表1-1。
表1-1 1s内基本时间复杂度
|
n的大小 |
1s内可以求出解的时间复杂度 |
|
10 |
n!(通常是一些搜索算法) |
|
20 |
2^n |
|
100 |
n³ |
|
1000 |
n²;n²㏒n |
|
10000 |
n√n |
|
100000 |
n㏒n |
|
1000000 |
n |
现在我们来看一个简单的问题:
一间实验室里有n盏灯,分别编号为1、2、3、……、n号,它们起初都是关着的。现在有学号为1、2、3、……、n号的学生分别走进这间实验室。1号学生把所有的灯的开关都拉了一次;2号学生把偶数号的灯的开关又都拉了一次;3号学生把倍数是3的号数的灯的开关都拉了一次;4号学生把倍数是4的号数的灯的开关都拉了一次;……当这n个学生全部走进了实验室之后,最后亮着的灯有多少盏?
如果无视时空复杂度,这题简直简单到了一种程度:只要使用一个[1..n]的布尔数组,模拟一遍即可。时间复杂度为O(n²)。但如果我告诉你:这题100%的数据,N≤100000。对照表1-1,就可以知道,1s内绝对无法解出来。
但是即使这个程序解不出所有数据,也要硬着头皮把程序写出来!(NOIP、NOI等竞赛真理),由于程序简单,所以很容易就写出来了。
var a:array[1..100000]of boolean; n,i,j:longint; begin readln(n); for i:=2 to n do for j:=i to n do if j mod i=0 then a[j]:=not(a[j]); for i:=1 to n do if a[i] then dec(n); writeln(n); end.
运行几组简单的数据,你会惊奇地发现,输出的数就是1..n的区间中完全平方数的个数!我们可以运用数学知识简单说明一下:
设一个完全平方数为y,则y分解质因数之后一定是类似于以下的形式:

运用约数个数定理,n的正约数的个数是:

可得,n的约数个数是
又:z_1,z_2,..z_n均为偶数,所以约数个数为奇数。即拉奇数次灯。
现在,程序只要将1..n的完全平方数个数求出,时间复杂度为O(1)。


浙公网安备 33010602011771号