文章目录
程序和算法的区别
算法是逻辑层,程序是物理层。
- 算法是对问题解决的分步描述。
- 程序是采用某种编程语言实显的,同一个算法通过不同程序员采用不同的编程语言,可以产生很多程序。
比较程序的好坏
只要从计算资源消耗的角度:更高效的利用计算资源或占用更少的计算资源。
什么是计算资源
- 算法解决问题工程中需要的储存空间或内存
- 算法的执行时间
import time
time.time()
'''记录了从1975年0点0分0秒到当前时间的时间,用此方法可以记录
程序的运行时间'''
算法时间度量指标
赋值语句是一个合适的算法度量指标
问题规模
影响算法执行时间的主要因素叫做问题规模。
在前n个整数累计求和计算算法中,需要累积的整数个数合适作为问题规模的指标。
“前100,00个整数求和对比前1,000个整数求和,算是同一个问题的更大规模”
算法分析的目标是找出问题规模会怎么影响一个算法得执行时间。
数量级函数 Order of Magnitude
基本操作数量函数T(n)的精确值并不是特别重要,重要的是T(n)中起决定性因素的主导部分
用动态的眼光看,就是当问题规模增大的时候,T(n)中的一些部分就会覆盖其他部分的贡献
大O表示法
数量级函数描述了T(n)中随着n增加而增加速度最快的主导部分。
计做O(f(n)),其中f(n)表示T(n)中的主导部分。
例1
以下为前n个整数求和函数,共有n+1次赋值。
def sum(n)
num=0
for i in range(1,n+1):
num+=i
return num
当n增大时,常数1再最终结果中显得越来越无足轻重。
所以可以去掉1,保留n作为主要部分,运行时间是O(n)
例2
假设某一算法T(n) = 5n²+27n+1005
当n趋近于正无穷时,5n²起绝对性作用,其他两项对结果的影响越来与小。
同样,二次项系数5对n²增长速度来说也影响不大。
所以可以在数量级中去掉27n+1005,以及系数5的部分,确定为O(n²)。
影响算法运行时间的其他因素
某些具体数据也会影响算法运行时间
针对算法输入数据而言,分为最好,最差和平均情况,平均情况体现了算法的主流性能
对算法的分析要看主流,而不能被几种特定的运行状况所迷惑。
常见大O数量级函数
当n非常小的时候,难以确定其数量级
例3以下赋值语句可以分为4个部分
a = 5
b = 6
c = 10
for i in range(n):
for j in range(n)
x = i *i
y = j * j
z = i *j
for k in range(n):
w = a* k + 45
v = b * b
d = 33
- 第一部分是三条赋值语句,执行3次
- 第二部分是双重循环,内部循环的循环体是三条计算语句,共执行n次 外层循环又将内层循环执行n次 所以第二部分的循环体共执行了3n²这么多次
- 第三部分是单层循环,执行2n次
- 第四部分是赋值语句,执行1次
T(n)=3+3n²+2n+1 →T(n)=3n²+2n+4
其他算法复杂度表示法
变位词判断问题
问题描述
所谓“变位词”是指两个词之间存在 组成字母的重新排列关系
为了简单起见,假设参与判断的两个词仅由小写字母构成,而且长度相等。
解题目标
写一个bool函数,以两个词作为参数,返回这两个词是否是变位词
可以很好的展示同一问题的不同数量级算法
解题思路
1.逐字检查法
原理思路
将1词中的字符逐个到词2中检查是否存在,存在就“打勾”标记(防止重复检查),如果每个字符都能找到则为变位词,如果有一个字符找不到,就不是变位词。
- 实现打勾标记的做法是将字匹配成功的字符变为“None”
代码实现
def anagramSolution(s1, s2):
alist = list(s2)
pos1 = 0
stillok = '{}与{}是变位词'.format(s1,s2)
while pos1 < len(s1) and stillok:
pos2 = 0
found = False
while pos2 < len(alist) and not found:
if s1[pos1] == alist[pos2]:
found = True
else:
pos2 += 1
if found:
alist[pos2] = None
else:
stillok = '{}与{}不是变位词'.format(s1,s2)
pos1 += 1
return stillok
算法分析
问题规模: 单词中包含的字符个数n
主要本分为双重循环部分: 外层循环遍历s1的每个字符,内层循环执行n次,而内层循环在s2中查找字符,每个字符的对比次数,分别是1至n中的一个,而且各不相同
执行总次数:
1
+
2
+
3
+
.
.
.
+
n
1+2+3+...+n
1+2+3+...+n
根
据
等
差
数
列
求
和
公
式
可
知
其
数
量
级
为
:
根据等差数列求和公式可知其数量级为:
根据等差数列求和公式可知其数量级为:
∑
i
=
0
n
i
=
n
(
n
+
1
)
n
=
1
2
n
²
+
1
2
→
O
(
n
²
)
\sum_{i=0}^ni=\frac{n(n+1)} {n}=\frac{1}{2} n²+\frac{1}{2}→O(n²)
i=0∑ni=nn(n+1)=21n²+21→O(n²)
2.排序比较
原理思路
将两个字符串按照字母顺序排序
逐个字符对比是否相同,如果想同则是变位词,有任何不同就不是变位词
代码实现
def anagramSoulution2(s1, s2):
alist1 = list(s1)
alist2 = list(s2)
alist1.sort()
alist2.sort()
pos = 0
matches = '{}与{}是变位词'.format(s1, s2)
while pos < len(s1) and matches:
if alist1[pos] == alist2[pos]:
pos += 1
else:
matches = '{}与{}不是变位词'.format(s1, s2)
return matches
算法分析
简单来看似乎只有一个循环,最多执行
n
n
n次,所以数量级是
O
(
n
)
O(n)
O(n)
但
是
之
前
的
排
序
语
句
并
不
是
无
代
价
的
,
排
序
算
法
采
用
不
同
解
决
方
案
运
行
时
间
的
数
量
级
差
不
多
是
但是之前的排序语句并不是无代价的,排序算法采用不同解决方案运行时间的数量级差不多是
但是之前的排序语句并不是无代价的,排序算法采用不同解决方案运行时间的数量级差不多是O(n²
)
或
者
)或者
)或者O(n log n)
,
大
于
循
环
的
,大于循环的
,大于循环的O(n)
,
所
以
本
算
法
主
导
步
骤
是
排
序
的
步
骤
,所以本算法主导步骤是排序的步骤
,所以本算法主导步骤是排序的步骤
所以本算法的运行事件数量及等于排序过程数量级为
O
(
n
l
o
g
n
)
O(n log n)
O(nlogn)
3.暴力法
解题思路
穷举所有可能组合
将s1中出现字符进行全排列,再查看s2是否出现在全排列的列表中
这其中最大困难是产生s1所有字符的前排列
根据概率论知识可知,如果n个字符进行全排列,其可能的字符串个数为:
n
!
n!
n!
暴力法不是个好的算法
对于2个字符长的单词来说,将产生
20
!
=
2
,
432
,
902
,
008
,
176
,
640
,
000
20!=2,432,902,008,176,640,000
20!=2,432,902,008,176,640,000
个候选词,如果每微妙处理1个候选词的话,需要将近8万年完成全部匹配。
4.技术比较
解题思路
对比两个单词中每个字母出现的次数,如果26个字母出现的次数都相同,则是变位词,否则不是变位词
为每个词设计一个26位的计数器,检查每个词,