1.算法基础
算法特性
- 有穷性:算法是由若干条指令组成的有穷序列,总是在执行若干次后结束,不可能
永不停止。 - 确定性:每条语句有确定的含义,无歧义。
- 可行性:算法在当前环境条件下可以通过有限次运算实现。
- 输入输出:有零个或多个输入,一个或多个输出。
衡量算法
时间复杂度: 算法运行需要的时间,一般将算法的执行次数作为时间复杂度的度量标准。
空间复杂度: 算法占用空间的大小。一般将算法的辅助空间作为衡量空间复杂度的标准。
算法占用的存储空间包括:
- 输入/输出数据;
- 算法本身;
- 额外需要的辅助空间
常见的算法复杂度
- 常数阶。常数阶算法运行的次数是一个常数,如 5、20、100。
- 多项式阶。很多算法时间复杂度是多项式,通常用 О(n)、О(n )、 О(n )等表示
- 指数阶。指数阶时间复杂度运行效率极差。
- 对数阶。对数阶时间复杂度运行效率较高,常见的有 О(logn)、О(nlogn)等
$$О(1)< О(logn)< О(n)< О(nlogn) < О(n2)< О(n3)< О(2n) < О(n!)< О(nn)$$
兔子数列
假设第 1 个月有 1 对刚诞生的兔子,第 2 个月进入成熟期,第 3 个月开始生育兔子,而
1 对成熟的兔子每月会生 1 对兔子,兔子永不死去……那么,由 1 对初生兔子开始,12 个月
后会有多少对兔子呢?兔子数列即斐波那契数列
实现
递归实现
1 | int fib1(int n) { |
时间复杂度较高
算法改进
1 | int fib2(int n) { |
指数阶时间复杂度降到多项式阶复杂度,空间复杂度降到$ O(n) $
迭代法
1 | int fib3(int n) { |
时间复杂度为$O(n)$,空间复杂度降到$O(1)$
马克思手稿中的数学题
马克思手稿中有一道趣味数学问题:有 30 个人,其中有男人、女人和小孩,这些人在
一家饭馆吃饭花了 50 先令;每个男人花 3 先令,每个女人花 2 先令,每个小孩花 1 先令;
问男人、女人和小孩各有几人?
由题可得以下方程:
$$ x+y+z=30 $$
$$ 3x+2y+x=50 $$
两式相减得:
$$ 2x+y=20 $$
x的取值范围是1~9,由此可设计出算法
1 | int main(int argc, char *argv[]) { |
时间复杂度为$ O(1) $,空间复杂度也为$ O(1) $。
爱因斯坦的阶梯
爱因斯坦家里有一条长阶梯,若每步跨 2 阶,则最后剩 1 阶;若每步跨 3 阶,则最后剩
2 阶;若每步跨 5 阶,则最后剩 4 阶;若每步跨 6 阶,则最后剩 5 阶。只有每次跨 7 阶,最
后才正好 1 阶不剩。请问这条阶梯共有多少阶?
1 | int main(int argc, char *argv[]) |
算法改进:
1 | int main(int argc, char *argv[]) |
哥德巴赫猜想
哥德巴赫猜想:任一大于 2 的偶数,都可表示成两个素数之和。
验证:2000 以内大于 2 的偶数都能够分解为两个素数之和。
素数测试的算法可采用试除法,即用 2,3,4,…, n 去除 n,如果能被整除则为合数,不能被整除则为素数。
1 | bool prime(int n) { |



