第02章 算法分析

文章介绍了算法分析的重要性,通过比较两个计算前n项和的程序,阐述了时间作为评判程序优劣的依据,并引出了时间复杂度的概念。大O表示法用于描述算法的效率,忽略低阶和常数因素,关注问题规模的增长。文中还提供了异序词检测的三种方法,分别分析了它们的时间复杂度:清点法为O(n^2),排序法为O(nlogn),计数法为O(n)。
摘要由CSDN通过智能技术生成

Chapter02 算法分析

来科大讯飞实习一个星期了,之前面试喜马拉雅和百度因为数据结构和算法挂了,为了后面能找到工作,开始养写博客的习惯。大家一起学习吧!!!

何为算法分析

思考第一个问题:现在有两个程序实现了同一个问题,请问,这两个程序有没有好坏?

答案:显然有,那么评判的标准是什么?

举例说明:

现在实现计算一个前n项和的程序

代码1

from timeit import Timer

def my_sum(n):
    my_sum = 0
    n = 100
    for i in range(1, n+1):
        my_sum += i
    return my_sum
time = Timer('my_sum(100)', 'from __main__ import my_sum')
print(time.timeit(1000000))
# 结果: 4.5124388

代码2

from timeit import Timer

def my_sum(n):
    return n*(1+n)/2
time = Timer('my_sum(100)', 'from __main__ import my_sum')
print(time.timeit(1000000))
# 结果: 0.1856523

代码的解释说明:

代码1利用暴力求解计算了1000000次求前100项和的时间结果

代码2利用前n项和求解了1000000次求前100项和的时间结果

显然两个代码有好有坏,而且经过上面的结果显示,明显有一个很好的判断条件——就是时间

但是如果大家拿去运行我上面的代码,就会出现一个问题,可能测试的时间跟我上面提供的结果不相同,显然第一个是因为计算机的性能原因,第二个是误差所致,此外,还有可能你的电脑可能运行其他的程序,导致占用了这里的速度,也会导致一个结果的不精确,因此,我们需要一个比较理性的分析结果——就是时间复杂度(看下文)。

大O表示法

我们要尝试拜托程序或计算机的影响,来描述算法的效率,也就是说我们要量化操作的步骤。把每一次的赋值操作看成一个计算单位,那么算法的执行时间也就被描述成所需的步骤数了。

拿上面的代码1举例,我们有两个赋值语句my_sum = 0n = 100,此外还有一个循环语句里面的赋值语句 my_sum += i,那么我们就需要运行(1+1+n)次赋值语句,我们用函数来描述它,定义成函数T,则 T ( n ) = 2 + n T(n)=2+n T(n)=2+n,这为叫做问题规模。但是这个没有其实还不够精简,因为当n很大时,2显得很没用。因此我们直接使用数量级的比较,即大O表示法,可以用O(n)来表示,这个O来自order单词。大O表示法是说明问题规模中起决定性作用部分的表示。

举一个例子:

T ( n ) = 5 n 2 + 27 n + 1005 T(n)=5n^2+27n+1005 T(n)=5n2+27n+1005,当n很大时,27n+1005其实影响不了其问题规模,另外当n很大时系数5也不是那么重要了,因此会直接使用 O ( n 2 ) O(n^2) O(n2)

举几个常见的大O表示法的函数

f(n)名称
1常数
log ⁡ n \log n logn对数
n线性
n log ⁡ n n \log n nlogn对数线性
n 2 n^2 n2平方
n 3 n^3 n3立方
2 n 2^n 2n指数

以上结果是复杂度递增的顺序。

案例:异序词检测

异序词:一个单词与另一个单词的使用的字母与数量完全相同,只是修改了顺序,那么这两个单词就被叫做异序词。例如heart与earth

实现异序词的方法很多

方案一:清点法

说白了就是循环一个单词,看看其字母在不在另一个里面,不在就不是,在的话就删除第二个单词中的这个字母一直进行

代码

def test(word1, word2):
    word1 = list(word1)
    word2 = list(word2)
    
    for w in word1:
        if w in word2:
            # 如果在就删除这个字母
            word2.remove(w)
        else:
            # 不在word2中
            return False
    # 都循环完了还要检测word2还有没有单词
    if len(word2) == 0:
        return True
    else:
        return False
    
if __name__ == '__main__':
    word1 = 'earth'
    word2 = 'heart'
    print(test(word1, word2))

方案2:排序法

原理就是先对单词进行排序,排序完后一一比对

def test(word1, word2):
    word1 = list(word1)
    word2 = list(word2)
    
    word1 = sorted(word1)
    word2 = sorted(word2)
    return word1 == word2
    
    
if __name__ == '__main__':
    word1 = 'eet'
    word2 = 'tte'
    print(test(word1, word2))

方案三:计数法

这个方案的原理是异序词有相同的单词次数,所以我们只要比较每个字符出现的次数即可

代码

def test(word1, word2):
    # 先给26个字母腾个位置
    c1 = [0] * 26
    c2 = [0] * 26
    
    for i in range(len(word1)):
        pos = ord(word1[i]) - ord('a')
        c1[pos] += 1
        
    for i in range(len(word2)):
        pos = ord(word2[i]) - ord('a')
        c2[pos] += 1
        
    for i in range(26):
        if c1[i] != c2[i]:
            return False
    return True
    
    
if __name__ == '__main__':
    word1 = 'earth'
    word2 = 'heart'
    print(test(word1, word2))

大家思考一下上面三个方案,用大O表示法都应该是多少?

答案是 O ( n 2 ) O(n^2) O(n2) O ( n log ⁡ n ) O(n\log n) O(nlogn) O ( n ) O(n) O(n),大家可能不理解,第一个不是只用了一个循环吗?,第二个都没用循环,第三个可能会写对,事实上,第一种方案使用了in,在list中使用in其实底层使用了for判断,第二个看似没有循环,但是排序没有代价吗?因为python的内部实现也必然有一部分并不是 O ( 1 ) O(1) O(1)的实现,具体内部实现的复杂度我下面贴一个链接,大家可以去看看。

python内部实现的时间复杂度页面:http://wiki.python.org/moin/TimeComplexity

内容来源于《python数据结构与算法》 第二版的第二章,删减了比较多,想看更详细的可以看原版,这本书的笔记我会更新完的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值