• python刷算法的一些骚操作(一)


    前言

    对于leetcode里面的一些优秀代码的阅读,有利于学习新的知识点,这篇文章是为了进行总结学习和方便查询的。
    另外,在python刷leetcode中,不需要单独引用包,直接使用就行。

    内容

    默认字典——defaultdict

    python中defaultdict用法详解
    库引用:

    from collections import defaultdict
    
    • 1

    defaultdict可以避免python中常规查找dict中不存在的key报错的问题,defaultdict的作用是在于,当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值。
    defaultdict接受一个工厂函数作为参数,如下来构造:

    dict =defaultdict(factory_function)
    dict1 = defaultdict(int)
    dict2 = defaultdict(set)
    dict3 = defaultdict(str)
    dict4 = defaultdict(list)
    dict5 = defaultdict(bool)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这个factory_function可以是listsetstr等等,作用是当key不存在时,返回的是工厂函数的默认值,比如list对应[ ]str对应的是空字符串,set对应set( )int对应0bool对应False

    申请嵌套defaultdict

    # 方法一
    defaultdict(lambda: defaultdict(list))
    # 方法二
    defaultdict(partial(defaultdict, list)) # 偏函数,第一个参数为函数,剩余的参数为对应的函数参数,如果有关键字也需要带上
    
    • 1
    • 2
    • 3
    • 4

    双端队列——deque

    python中deque模块详解
    python collections 模块中的 deque
    库引用:

    from collections import deque
    
    • 1

    deque 是双边队列 ( d o u b l e − e n d e d q u e u e ) (double-ended queue) (doubleendedqueue),具有队列和栈的性质,在list的基础上增加了移动旋转增删等。
    创建

    from collections import deque
    
    d=deque()
    d=deque(maxlen=20) # 当超过最大长度时另一侧元素会被删除
    d=deque('12345')  # 则d=deque(['1', '2', '3', '4', '5'])
    
    • 1
    • 2
    • 3
    • 4
    • 5

    其他方法

    d = collections.deque([])
    d.append('a') # 在最右边添加一个元素,此时 d=deque('a')
    d.appendleft('b') # 在最左边添加一个元素,此时 d=deque(['b', 'a'])
    d.extend(['c','d']) # 在最右边添加所有元素,此时 d=deque(['b', 'a', 'c', 'd'])
    d.extendleft(['e','f']) # 在最左边添加所有元素,此时 d=deque(['f', 'e', 'b', 'a', 'c', 'd'])
    d.pop() # 将最右边的元素取出,返回 'd',此时 d=deque(['f', 'e', 'b', 'a', 'c'])
    d.popleft() # 将最左边的元素取出,返回 'f',此时 d=deque(['e', 'b', 'a', 'c'])
    d.rotate(-2) # 向左旋转两个位置(正数则向右旋转),此时 d=deque(['a', 'c', 'e', 'b'])
    d.count('a') # 队列中'a'的个数,返回 1
    d.remove('c') # 从队列中将'c'删除,此时 d=deque(['a', 'e', 'b'])
    d.reverse() # 将队列倒序,此时 d=deque(['b', 'e', 'a'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    优先队列——heapq

    python中使用优先队列
    注:默认heapq只支持小顶堆,虽然也支持大顶堆,但是默认会出现问题,因此取最大我们可以在存储的时候取负数,取出的时候还原进行操作。

    创建堆

    两种方法:逐个加入或使用list加入。

    import heapq
    # 第一种
    nums = [2, 3, 5, 1, 54, 23, 132]
    heap = []
    for num in nums:
        heapq.heappush(heap, num)  # 加入堆
    
    print(heap[0])  # 如果只是想获取最小值而不是弹出,使用heap[0]
    print([heapq.heappop(heap) for _ in range(len(nums))])  # 堆排序结果
    # out: [1, 2, 3, 5, 23, 54, 132]
    
    # 第二种
    nums = [2, 3, 5, 1, 54, 23, 132]
    heapq.heapify(nums)
    print([heapq.heappop(nums) for _ in range(len(nums))])  # 堆排序结果
    # out: [1, 2, 3, 5, 23, 54, 132]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    实例

    import heapq
    
    tasks = []
    heapq.heappush(tasks,(10,'aaa'))
    heapq.heappush(tasks,(40,'bbb'))
    heapq.heappush(tasks,(30,'ccc'))
    heapq.heappush(tasks,(20,'ddd'))
    
    while tasks:
        task = heapq.heappop(tasks)
        print(task)
    # 输出
    # (10, 'aaa')
    # (20, 'ddd')
    # (30, 'ccc')
    # (40, 'bbb')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在sorted方法里,它的排序算法是通过比较第一个元素的大小,小的排在前面,第一个元素相同再比较第二个元素,看返回之前的代码,heapq.heappush 将set元素添加到列表元素以后,将对其进行重新排序,将最小的放在前面,于是就得到了上面的打印结果。

    上面是使用python自带的 set 数据结构,可否自定义一种类型呢,比较在实现生活中,在上班的第一件事是给自已写一下今天要完成哪些事情,其实哪些事情的优先级比较高就是先做哪些事情,其实在上面也说到 sorted 方法,这个方法其实就是在调用对象的 cmp 方法,好么我可以单独定义一个带有 cmp 方法的对象则可以实现优先队列中的对象排序。

    import heapq
    
    # 使用heapq实现优先队列
    #定义一个可比较对象
    class CompareAble:
        def __init__(self,priority,jobname):
            self.priority = priority
            self.jobname = jobname
    
        def __cmp__(self, other):
            if self.priority < other.priority:
                return -1
            elif self.priority == other.priority:
                return 0
            else:
                return 1
    
    
    joblist = []
    
    heapq.heappush(joblist,CompareAble(80,'eat'))
    heapq.heappush(joblist,CompareAble(70,'a write plan2'))
    heapq.heappush(joblist,CompareAble(70,'write plan'))
    heapq.heappush(joblist,CompareAble(90,'sleep'))
    heapq.heappush(joblist,CompareAble(100,'write code'))
    
    while joblist:
        task = heapq.heappop(joblist)
        print(task.priority,task.jobname)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    列表——list

    切片

    语法:[start:stop:step]
    距离

    a = a[::-1] # 翻转
    
    • 1

    append问题

    在 Python 中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,Python并没有拷贝这个对象,而只是拷贝了这个对象的引用,我们称之为浅拷贝
    这种情况尤其注意在递归回溯的时候使用,比如listappend方法,为防止这种情况,需要使用深拷贝

    li.append(copy.deepcopy(num))
    
    • 1

    创建多维数组

    (2020/12/30)这个bug找了一下午才被同学帮忙找出来,进行记录一下。
    python中的[0]*n是浅拷贝,也就是把一个列表重复了 n n n次,[0 for _ in range(n)]是创建,深拷贝。
    如何创建二维数组 以及 python中[0 ]* n与[0 for _ in range(n)]的区别与联系
    生成一维数组(都阔以)

    dp1 = [0]*n 
    dp2 = [0 for _ in range(n)]
    
    • 1
    • 2

    生成二维数组

    dp1 = [[0] * n ] * m # 每一行改变其他行也会发生改变
    dp2 = [[0 for _ in range(n) ] for _ in range(m)] # 深拷贝
    dp3 = [[0] * n for _ in range(m)] # 深拷贝
    
    • 1
    • 2
    • 3

    nums和nums[:]

    n u m s = A nums = A nums=A更改nums这一变量名所指的对象,让nums变量指向A所指向的对象;
    n u m s [ : ] = A nums[:] = A nums[:]=A对nums指向的对象赋值,把A变量指向的对象的值逐个复制到nums指向的对象中并覆盖nums指向的对象的原来值。
    注:需要更改nums的值时候请使用nums[:]而不是nums。

    计数——Counter

    虽然在实际情况中需要对出现的字符进行统计计数,可以遍历一遍使用字典处理;但是直接使用Counter函数它不香嘛。
    结论:推荐使用全部用循环或者组合的方式(里面是×,外面循环)的方式。如果都为乘的方式是浅复制,每一行的改变都会改变其他行。(好吧,为了代码简洁,我想我还是使用组合的方法吧!)

    from collections import Counter
    data = ['a','2',2,4,5,'2','b',4,7,'a',5,'d','a','z']
    c = Counter(data)
    print(c) # Counter({'a': 3, '2': 2, 4: 2, 5: 2, 2: 1, 'b': 1, 7: 1, 'd': 1, 'z': 1})
    print(type(c)) # 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    排序——sorted

    a = [[2,3],[4,1],(2,8),(2,1),(3,4)]
    b = sorted(a,key=lambda x: (x[0], -x[1]))
    
    • 1
    • 2

    python 排序 sorted 如果第一个条件 相同 则按第二个条件排序

    排序模块——bisect

    按已排序列表要求进行操作。且bisect是python内置模块,用于有序序列的插入查找

    • 查找
      对于非重复元素:
    import bisect
    
    data = [1,4,6,8]
    print(bisect.bisect(data,3)) # 1(查找该原则将会插入的位置,原列表不会发生改变)
    print(data) # [1, 4, 6, 8]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    那么插入元素已存在怎么办:

    import bisect
    
    data = [1,4,6,8]
    print(bisect.bisect(data,4)) # 2
    print(data) # [1,4,6,8]
    
    data = [1,4,6,6,6,8]
    print(bisect.bisect(data,6)) # 5
    print(data) # [1,4,6,6,6,8]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注:感觉默认对于已存在元素会查找后面的位置。
    对于重复的情况, bisect_left 和 bisect_right 函数这两个函数用入处理将会插入重复数值的情况,返回将会插入的位置:

    data = [1,4,6,8]
    print(bisect.bisect_left(data,4)) # 1
    print(bisect.bisect_right(data,4)) # 2
    print(data) # [1,4,6,8]
    
    • 1
    • 2
    • 3
    • 4
    • 插入
      对于非重复元素:
    import bisect
    
    data = [1,4,6,8]
    print(bisect.insort(data,3)) # None
    print(data) # [1,3,4,6,8]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    对于插入重复元素:

    import bisect
    
    data = [1,4,6,8]
    print(bisect.insort(data,4)) # None
    print(data) # [1,4,4,6,8]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    好吧,对于插入元素分不清前后了,不过pyhton还是提供了insort_left和insort_right函数,虽然操作结果一样,但是两者插入的位置是不同的。

    import bisect
    
    data = [1,4,6,8]
    print(bisect.insort_left(data,4)) # None
    print(data) # [1,4,4,6,8]
    data = [1,4,6,8]
    print(bisect.insort_right(data,4)) # None
    print(data) # [1,4,4,6,8]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    最值——最大值和最小值

    # 整型
    import sys
    
    max_int_value = sys.maxsize
    min_int_value = -sys.maxsize - 1
    
    # 浮点型
    max_float_value = float('inf')
    min_float_value = float('-inf')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    缓存机制——functools.lru_cache

    @functools.lru_cache(maxsize=None, typed=False)
    
    • 1

    使用functools模块的lur_cache装饰器,可以缓存最多maxsize个此函数的调用结果,从而提高程序执行的效率,特别适合于耗时的函数。
    Python 缓存机制与 functools.lru_cache

    排列组合——comb,itertools

    调用scipy计算排列组合的具体个数

    from scipy.special import comb, perm
    
    perm(3, 2) # 排列6.0
    
    comb(3, 2) # 组合3.0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    调用 itertools 获取排列组合的全部情况

    from itertools import combinations, permutations
    
    permutations([1, 2, 3], 2)
    <itertools.permutations at 0x7febfd880fc0> # 可迭代对象
    list(permutations([1, 2, 3], 2)) # 排列 [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
    list(combinations([1, 2, 3], 2)) # 组合 [(1, 2), (1, 3), (2, 3)]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Python 排列组合的计算

    字符与ASCII码转换

    c = 'a'
    a = 101 
    print( c + " 的ASCII 码为", ord(c)) # 97
    print( a , " 对应的字符为", chr(a)) # e
    
    • 1
    • 2
    • 3
    • 4

    字母大小写转换

    注意:只会转换字母,其他字符直接进行忽略不变

    'AbC'.upper()  # ABC
    'AbC'.lower()  # abc
    
    • 1
    • 2

    判断字符串是否为字母或数字

    # isdigit()函数判断是否为数字(无法判断负数)
    '2'.isdigit()  # True
    '-2'.isdigit() # False
    # isalpha()函数判断是否为字母
    'abc'.isalpha() # True
    'Abc'.isapha()  # True
    # isalnum()函数判断是否为数字和字母的组合
    '123'.isalnum()   # True
    'Abc'.isalnum()   # True
    '123Abc'.isalnum()# True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    后记

    更多信息可查看索引python的一些高级操作汇总

  • 相关阅读:
    全志XR806+TinyMaix,在全志XR806上实现ML推理
    Step 3.1:垃圾收集器与内存分配策略
    Python列表操作指南:索引、切片、遍历与综合应用
    Postman使用总结
    在嵌入式开发中如何提高自己的代码水平
    解决高并发问题
    NEDC、WLTC、CLTC,三种汽车能源消耗测试标准有什么区别?
    Android【SDK】 SDK是如何开发的,怎么打包aar包
    【数字IC验证快速入门】12、SystemVerilog TestBench(SVTB)入门
    【高等数学】五、微分方程
  • 原文地址:https://blog.csdn.net/XZ2585458279/article/details/126476278