1.时间复杂度_Python

算法概述

Best Practices

Top tips

  • 算法:在计算机领域里,算法是一系列程序指令,用于处理特定的运算和逻辑问题

    衡量算法优劣的主要标准是时间复杂度和空间复杂度

  • 数据结构:数据的组织、管理和存储格式,其使用目的是为了高效的访问和修改数据

    数据结构包含数组、链表这样的线性数据结构,也包含树、图这样的复杂数据结构

  • 时间复杂度:对一个算法运行时间长短的量度,用大O标识,记作T(n)=O(f(n))

    常见的时间复杂度按照从低到高的顺序,包括O(1)、O(log n)、O(n)、O(n²)、O(n³)、O(2^n)、O(n!)

  • 空间复杂度:对一个算法在运行过程中临时占用存储空间大小的量度,用大O表示,记作S(n)=O(f(n))

    常见的空间复杂度按照从低到高的顺序,包括O(1)、O(n)、O(n²)等。其中递归算法的空间复杂度和递归深度成正比

时间复杂度

时间复杂度

主定理

主定理

  • 二分查找:数列本身有序,并在这个有序的数列找到你要的数,每次都一分为二,只查一边(O(log n))

  • 二叉树遍历:每次要一分为二,每一边都是相等的时间复杂度(O(n))

    二叉树遍历每一个节点都访问一次且仅访问一次

  • 已排序的二维矩阵:二分查找,一维数组查找(O(log n)),二维矩阵查找(O(n))

  • 归并排序:排序最优的办法(O(n log n))

思考题

  1. 二叉树遍历-前序、中序、后序:时间复杂度是多少?

    (O(n))n代表二叉树里面的节点总数

    不管是前序、中序、后序,它遍历二叉树的时候,每个节点都会访问一次且仅访问一次,所以它的时间复杂度就是线性于二叉树的节点总数,也就是(O(n))的时间复杂度

  2. 图的遍历:时间复杂度是多少?

    (O(n))n代表图的节点总数

    图里面的每一个节点访问一次且仅访问一次,所以时间复杂度为(O(n))

  3. 搜索算法:DFS、BFS时间复杂度是多少?

    (O(n))n代表搜索空间的节点总数

    DFS(深度优先)、BFS(广度优先),每一个节点只访问一次,所以时间复杂度为(O(n))

  4. 二分查找:时间复杂度是多少?

    (O(log n)) 每次都一分为二,只查一边

空间复杂度

  1. 数组的长度

    数组的长度基本上就是空间复杂度,一维数组O(n)、二维数组O(n²)

  2. 递归的深度

    递归最深的深度就是空间复杂度的最大值

练习

爬楼梯
“变位词”判断问题

”变位词“:两个词之间存在组成字母的重新排列关系

  1. 逐字检查

    解法思路:将词1中的字符逐个到词2中检查是否存在,存在就”打勾“标记(防止重复检查)。如果每个字符都能找到,则两个词就是变位词,只要有1个字符找不到,就不是变位词

    程序技巧:实现“打勾”标记:将词2对应字段设为None,由于字符串是不可变类型,需要先复制到列表中

    时间复杂度:O(n²)

    def anagramSolution1(s1, s2):
        alist = list(s2)
        pos1 = 0
        stillOK = True
        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 = False
            pos1 += 1
        return stillOK
    
    print(anagramSolution1("abcd", "dcba"))
    
  2. 排序比较
    解法思路:将两个字符串都按照字母顺序排好序,再逐个字符对比是否相同,如果相同则是变位词,有任何不同就不是变位词

    时间复杂度:O(n log n)

    def anagramSolution1(s1, s2):
        alist1 = list(s1)
        alist2 = list(s2)
    
        alist1.sort()
        alist2.sort()
        pos = 0
        matches = True
        while pos < len(s1) and matches:
            if alist1[pos] == alist2[pos]:
                pos += 1
            else:
                matches = False
        return matches
    
    print(anagramSolution1("abcd", "dcba"))
    
  3. 暴力法

    解题思路:穷尽所有可能组合。将s1中出现的字符进行全排列,再查看s2是否出现在全排列列表中,根据组合数学结论,如果n个字符进行全排列,其所有可能得字符串个数为n!

  4. 计数比较

    解题思路:对比两个词中每个字母出现的次数,如果26个字母出现的次数都相同的话,这两个字符串就一定是变位词

    时间复杂度:O(n)

    def anagramSolution1(s1, s2):
        c1 = [0] * 26
        c2 = [0] * 26
        for i in range(len(s1)):
            pos = ord(s1[i]) - ord('a')
            c1[pos] = c1[pos] + 1
        for i in range(len(s2)):
            pos = ord(s2[i]) - ord('a')
            c2[pos] = c2[pos] + 1
        j = 0
        stillOK = True
        while j < 26 and stillOK:
            if c1[j] == c2[j]:
                j += 1
            else:
                stillOK = False
        return stillOK
    
    print(anagramSolution1("abcd", "dcba"))
    

Python数据类型的性能

类型listdict
索引自然数i不可变类型值key
添加append、extend、insertb[k]=v
删除pop、remove*pop
更新a[i]=vb[k]=v
正查a[i]、a[i:j]b[k]、copy
反查index(v)、count(v)
其它reverse、sorthas_key、update

创建一个Timer对象,指定需要反复运行的语句和只需要运行一次的“安装语句”

然后调用这个timeit方法,其中可以指定反复运行多少次

from timeit import Timer

def test1():
    l = []
    for i in range(1000):
        l = l + [i]
def test2():
    l = []
    for i in range(1000):
        l.append(i)
def test3():
    l = [i for i in range(1000)]
def test4():
    l = list(range(1000))

t1 = Timer("test1()", "from __main__ import test1")
print(f"concat {t1.timeit(number=1000)} seconds\n")
t2 = Timer("test2()", "from __main__ import test2")
print(f"append {t2.timeit(number=1000)} seconds\n")
t3 = Timer("test3()", "from __main__ import test3")
print(f"comprehension {t3.timeit(number=1000)} seconds\n")
t4 = Timer("test4()", "from __main__ import test4")
print(f"list range {t4.timeit(number=1000)} seconds\n")

列表时间复杂度
列表时间复杂度
字典时间复杂度
字典时间复杂度

  • 可见字典的执行时间与规模无关,是常数
  • 而列表的执行时间则随着列表的规模加大而线性上升
import timeit
import random

for i in range(10000, 1000001, 20000):
    t = timeit.Timer(f"random.randrange({i}) in x", "from __main__ import random,x")
    x = list(range(i))
    lst_time = t.timeit(number=1000)
    x = {j:None for j in range(i)}
    d_time = t.timeit(number=1000)
    print(f"{i,lst_time,d_time}")

参考链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值