引言
最近在复刷LeetCode,某种意义上做题要做得快,对STL保持熟悉度是蛮重要的,至少在求和、排序、查找时就不用重复敲代码了。于是,整理了部分常用python算术/数据结构/数理模块,以及相应的对TLE敏感的操作,希望能帮助到其它人。
python内建函数
format():格式化输出函数(在控制输出精度和空格补齐等问题中很好用)round(x):四舍五入cmp(x, y):比较2个对象,如果 返回 , 如果 返回 , 如果 返回abs(x)/max()/min():绝对值/最大值/最小值len():返回对象的长度,如列表、字典等range(start=0, stop, step=1]):返回一个可迭代对象,常用于for循环sum(iterable): 求和函数pow(x, y, [z]):求幂函数 ,运算完毕可以顺带对z取模;大数取模问题可以直接ACsorted(iterable, key, reverse):采用Timsort的稳定排序算法,默认升序;该函数太重要了,请多写写代码研究一下它的各个参数isinstance(obj, type):判断类型all(iterable)/any(iterable):迭代与操作/迭代或操作(0、1、None均等价于False)int(x, base=10))/float()/str():转整数(可自定义进制)/转浮点数/转字符串bin()/oct()/hex():10进制转二进制(返回0b开头的字符串)/10进制转八进制(返回0开头的字符串)/10进制转十六进制(返回0x开头的字符串)ord()/chr():字符转ASCII或ASCII转字符complex(real, imag):创建一个复数,不过现在可以直接通过语法糖创建,eg:1+2jdivmod():函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)eval(expression, [globals, locals]):执行一个字符串表达式,并返回表达式的值,eg:eval('pow(2, 2)');在某些字符串解析题中非常好用,详细可见>此处<map(function, iterable...):映射函数,需要注意的是在Python3中返回一个迭代对象而不再是一个列表filter(function, iterable):过滤函数reduce(function, iterable, [initializer]):累积函数,现在被归类到functools模块中zip(iterable, ...):将对象中对应的元素打包成一个个元组,常用于并联取值,详见下文的【注意事项】hash(obj):返回哈希码,常用于对象比较或将其转化为唯一的索引(不过更推荐使用id()完成该需求)id():返回对象的唯一标识符,和hash()类似,但更鲁棒更快且可以对list、def等对象求idenumerate():将一个可遍历的数据对象组合为一个索引序列,eg:for i, v in enumerate(list_a):
注意事项:
- 标准输出函数
print(*objects, sep=' ', end='\n')可以通过设置seq标志位来设定间隔字符、设置end来设定结尾字符,常用于进行灵活的输出。对列表输出时,也常用' '.join(result_list)来快速输出一个串,而不用挨个遍历。 - 需要注意的是,若从
range()中取遍历指示器,在Python 3中,在for循环内重复定义迭代变量不影响迭代遍历的值,如:
# (Python 3)该段代码最终输出0 1 2三行,而不是只有一行0
for i in range(3): # 并不等价于C语言的 for(int i=0;i<3;i++)
print(i)
i += 10 # 内部遍历不影响作为循环i的值,这跟C语言差异很大,请留心
map、filter、reduce等函数式编程函数很重要,能够让你少敲很多代码,特别是filter在筛选题中有高的实用性。- 特别的,
float()可用来构造无限值,如float('inf')。 yield关键字也很重要,可用来创建生成器,在数列生成、斐波那契查找等用处很大,可以极大的节省开销。>举例一则<,>教程指南<。需要注意的是,当迭代器函数执行结束时,将自动抛出StopIteration异常,仅在 for 循环里,无需处理StopIteration异常,循环会正常结束,否则需要使用except关键字捕获。- 有些时候
try、except Exception as e、finally等语句可以直接避免在函数体里进行空值检定,大大减少敲键盘的时间开销:>举例一则<。 - 善用
set()来进行列表去重。 format()函数能方便你的格式化输出,如小数精度控制问题,请考虑>进行学习<。input()和raw_input()的区别在于对于python的两个版本(2/3)表现不一致,python 3请使用前者,接收到的数据默认为str。- 对于非对象类(如
list)变量,需要用global关键词在函数内使用全局变量。 del关键词会比list.pop(index)拥有更高的效率,属于TLE敏感的操作。list[::-1]语法糖可以快速对列表进行倒序,在字符串倒序等问题中有奇效;但list.reverse()更高效,属于TLE敏感的操作。(另外需要注意:后者是原地倒序)- 在python 3中,
zip()返回一个可迭代对象,需要手动list()以进行其它列表操作。 - 求均值、中位数、众数的API在
statistics模块中;求众数可以调用collections.Counter来实现。 - python默认的递归栈很有限,有时候会出现C语言能过而python不能过的情况,请>参考此处<解决这个问题——
maximum recursion depth exceeded in comparison。
算术模块
1. math
常量:
pi:圆周率 (3.141592653589793)inf:无限大nan:非数字(Not A Number)e:自然数tau:圆周率的两倍,用于计算弧度和角度的换算。( 弧度 )
常用方法:
floor(x):向下取整,eg:ceil(x):向上取整,eg:trunc(x):直接去除数字的小数部分,作用等同floorgcd(a, b):求最大公约数,返回值默认与 同号(b非0时);任一数为 时返回 ;pow(x, y):求幂( ),返回浮点数,eg:log(x, y):求对数 ,返回浮点数,eg:log2(x)/log10(x)/log1p(x):以 / 为底的对数;求自然对数radians:将角度转换为弧度sin/sinh:正弦cos/cosh:余弦tan/tanh:正切sqrt(x):平方根modf(x):返回浮点数 的小数和整数部分,eg:exp(x):指数函数 ,需要注意的是math.pow(math.e, x)精度会更高isnan/isinf/isfinite:常量检测函数,isfinite当检测数为inf和nan时返回False
注意事项:
math.fabs()和内建函数中的abs()相比,后者支持复数运算。复数的绝对值计算: 。divmod(a, b)与math.modf(x)相比,前者返回元组(a // b, a % b),后者拆分小数和整数部分;前者支持复数运算。math.pow()和内建函数中的pow()相比,前者运算为浮点型,后者会保留整形(还可以顺带取模)fractions.gcd()在Python 3后已被math.gcd()取代。- 最大公倍数:
(a * b) // gcd(a, b)。
2. cmath
复数运算模块,大部分API与math相同。
Python中构建复数的语法示例为:c = 1 + 1j,如:
a, b = 1+1j, 1-1j
print(a, b, a+b) # (1+1j) (1-1j) (2+0j)
3. bisect
二分查询算法模块,时间复杂度
。常用于有序序列(升序)的插入和查找。默认使用bisect_right()、insort_right()。
bisect_left(a, x, lo=None, hi=None)/bisect_right():在有序列表的a中查找值x并返回其索引,有左向和右向之分,分别当命中时返回左/右一位的索引,即bisect_left -> all e in a[i:] have e >= x、bisect_right -> all e in a[i:] have e > x。insort_left(a, x, lo=None, hi=None)/insort_right():在有序列表的a中插入值x并保证顺序。
a = [0, 1, 2, 3, 5, 6, 8, 17]
print(bisect.bisect_left(a, 4)) # 4
print(bisect.bisect_right(a, 4)) # [default] 4
print(bisect.bisect_left(a, 5)) # 4
print(bisect.bisect_right(a, 5)) # [default] 5
4. statistics
数据统计模块,补全了中位数、众数、方差的快速实现。同时支持下文的分数模块。
mean(): 数据的算术平均数(“平均数”)harmonic_mean()|:数据的调和均值median():数据的中位数(中间值)median_low():数据的低中位数median_high():数据的高中位数mode():数据的众数pstdev():数据的总体标准差pvariance():数据的总体方差stdev():数据的样本标准差variance():数据的样本方差
5. fractions
分数运算模块,>参考此处<。
构造方法:
class fractions.Fraction(numerator=0, denominator=1)
class fractions.Fraction(other_fraction)
class fractions.Fraction(float)
class fractions.Fraction(decimal)
class fractions.Fraction(string)
常用方法:
gcd(a, b):求最大公约数,返回值默认与 同号(b非0时);任一数为 时返回
注意事项:
fractions.gcd()在python3后已被math.gcd()取代,此处的API仅对python 2有效。
数据结构
6. heapq
堆模块,构建小顶堆。构建时直接传入一个列表作为堆结构,调用heapify等函数时会直接改变这个堆列表的内部顺序。
小顶堆:根节点的值小于等于其左右节点的值,即
a[k] <= a[2*k+1] and a[k] <= a[2*k+2]
heapify(heap):构建/调整一个堆heappop(heap):返回最小数heappush(heap, item):向堆内压入一个元素heappushpop(heap, item):向堆内压入一个元素后返回最小数heapreplace(heap, item):删除堆中最小元素并加入一个元素merge(*iterables):合并多个有序列表,并返回有序列表的迭代器(即需要手动list())nlargest(n, iterable, key):返回最大的n个数的列表nsmallest(n, iterable, key):返回最小的n个数的列表
技巧:如果要构建大顶堆,对入堆元素取负即可,如:
heap = [1, 2, 3, 4, 5]
heap = [-i for i in heap]
heapify(heap)
m = -heappop(heap) # 注意取负回来
另外需要注意,堆排序是不稳定的。
7. queue
队列模块,Queue其实不是很必要,完全可以用List的内建函数替代;比较有用的是其中的PriorityQueue,常用于解图结构相关的问题,如有向图最短距离等。特殊的,还有内建对象deque作为双向队列,本质是封装了collections.deque,此除不做讲解。
需要注意是的,queue模块中提供的是同步的类,因此其入列/出列运算速度是比较慢的,远不及list.insert()和list.pop()。
类:
-
Queue(maxsize=0)FIFO 队列。如果 maxsize 小于等于零,队列尺寸为无限大,下同。 -
LifoQueue(maxsize=0)LIFO 队列。 -
PriorityQueue(maxsize=0)优先级队列。
优先级队列:二叉堆,本质上就是一个小顶堆/大顶堆。
通用API:
qsize():返回队列大小full():队列是否满了put(item, block, timeout):以同步的方式入列get(item, block, timeout):以同步的方式出列put_nowait(item):以非同步的方式入列get_nowait(item):以非同步的方式出列
优先队列的
item应该为以下数据格式:(priority number, data)
8. collections
是Python内建的一个集合模块,提供了许多有用的集合类。该模块较为重要,为本文行文流畅考虑,此处仅做简介索引和用方举例。详细了解API可到:>扩展学习资料<
常用类:
namedtuple:构建一个可命名的tuple,该类型可用isinstance检定deque:高效实现插入和删除操作双向列表,比list优异,可直接改造成FIFO队列或栈,API与list基本相同ChainMap:将多个dict串成一个逻辑上的dict(不修改内存),往往用于优先级查找Counter: 计数器,大部分情况下速度会更快,但若只统计个别元素,推荐使用list.count(),接受一个字典或字符串OrderedDict: 有序字典(按key的值升序排序),常用来做一个FIFO的有序字典defaultdict: 访问缺失值时会返回一个默认值的字典而不是抛出KeyError,相当好用,其它行为与dict一致,可以看成是一种更健壮的dict
8.1 Counter
该类由于重载了加、减、del等运算,因此可以直接进行减操作,在对字符串进行统计时想当有用。
构造:
Counter():空构建Counter(st):传入一个字符串Counter(dict):传入一个字典Counter(key=v, ...):传入一些键值对
常用方法:
update(Counter):most_common(n):返回 最多的n个元素的列表
8.2 deque
当只对首位数据进行操作时,双向队列类比list有着更高的效率。其与list相比,用有几乎完全相同的API,只不过pop()不允许按index弹出数据,只能弹出队尾数据,并且多了以下API:
popleft():与pop()相对,从尾部弹出数据(没有发现存在比pop(0, data)明显的性能优势)appendleft():与append()相对,向首部添加数据(没有发现存在比insert(0, data)明显的性能优势)
注意事项:
collections.deque比queue.deque更加强大;后者是对前者的封装,作为模块内建对象存在,而前者这是一个类。后者拥有dequeue、enqueue等标准队列操作,但个人更推荐使用前者而不是后者。
函数式编程/编程风格优化
9. functools
高阶函数模块,对于数学题或函数式编程风格优化起到重要作用。
主要方法:
reduce(function, iterable, [initializer]):累积函数,常用于列表连续求积
其它方法跟装饰器有关,不一一罗列。
10. itertools
本模块实现了一系列 iterator,比起手动for循环,会快很多。
无穷迭代器:
count(start, [step]):步进迭代器,生成序列start, start+step, start+2*step...cycle(iterable):循环迭代器,输入迭代器p,生成序列p0, p1, ... plast, p0, p1, ...repeat(obj [,n]): 重复迭代器,重复无限次或n次,生成序列obj, obj, obj, ...
有限迭代器:
accumulate(iterable, [func]):创建一个迭代器,根据func返回累加和或其他二元函数的累加结果。eg:accumulate([1,2,3,4,5]) --> 1 3 6 10 15chain:创建一个迭代器,它首先返回第一个可迭代对象中所有元素,接着返回下一个可迭代对象中所有元素,直到耗尽所有可迭代对象中的元素,eg:chain('ABC', 'DEF') --> A B C D E Fcompress(data, selectors):返回 data 中经 selectors 真值测试为 True 的元素,eg:compress('ABCDEF', [1,0,1,0,1,1]) --> A C E Fdropwhile:从首次真值测试失败开始,eg:dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1takewhile:直到首次真值测试失败结束,eg:takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4filterfalse(predicate, iterable):返回iterable中predicate为False的元素,eg:`filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8groupby(iterable, [key]):迭代器中相邻的重复元素挑出来放在一起,eg:for i, v in itertools.groupby('AABBC'): print(i, list(v)) --> A ['A', 'A'] B ['B', 'B'] C ['C']islice(iterable, start, stop[, step]):返回从 iterable 里选中的元素,eg:islice('ABCDEFG', 2, None) --> C D E F Gstarmap(function, iterable):星映射迭代器,eg:starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000tee(iterable, n):拆分一个迭代器为 个zip_longest:创建一个迭代器,从每个可迭代对象中收集元素。如果可迭代对象的长度未对齐,将根据fillvalue填充缺失值,eg:zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
排列组合迭代器:
product:笛卡尔积,eg:product('ABCD, 2') --> AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DDpermutations:连续返回由 iterable 元素生成长度为 r 的排列,和combinations有点类似,即返回组合排列解,eg:permutations('ABCD, 2') --> AB AC AD BA BC BD CA CB CD DA DB DCcombinations:返回由输入iterable中元素组成长度为 的子序列,eg:combinations('ABCD', 2) --> AB AC AD BC BD CD
注意事项:
accumulate可通过给定一个func来自定义累加过程,例如给定max作为累加器,则统计的是至今为止最大的数,在一些题目中相当好用。combinations本质上就是就是计算组合数,在一些数学题中相当好用,例如print(len(list(itertools.combinations('ABCD', 2))))可以直接得到 ;permutations则是返回 。
专业导向
专业导向的模块除了
re以外,一般不怎么用到,只对于某些专业题目,如二进制、文件、时间、加密等。
11. datetime
时间模块,可以直接对日期进行加减等操作,在某些日期问题中非常有用。如二月份的日期加减:
print(datetime.date(2019, 2, 28) + datetime.timedelta(days=1))
# 2019-03-01
常用类:
date(year, month, day):日期模型time(hour, minute, second, microsecond, tzinfo):时间模型datetime(...):日期和时间的结合模型;常用timestamp()可将其转为时间戳timedelta(days, seconds, microseconds, milliseconds, minutes, hours, weeks):时间增量,常用total_seconds()可以将其转化为秒。timezone:时区类
12. calendar
主要用于构建日历,在诸如打印出某年第某月日历的题目时非常有用,如打印2020年第二个月的日历(注意并不是2月1号到2月29号,而是印刷日历的编号,即为1月27日到3月1日【打开你右下角的windows日历自行查查对】)
c = calendar.Calendar(firstweekday=0) # 0:日历印刷的第一天为星期一
for i in c.itermonthdates(2020, 2):
print(i)
13. struct
struct模块来解决bytes和其他二进制数据类型的转换。常用于处理二进制或字符串题。
14. re
在这些专业导向的模块中,正则模块则是最重要的模块,能处理大量字符串相关的题目,需要额外学习正则表达式,此处不再赘述,属于必须掌握的模块。请参考>本文档<进行学习。
15. copy
主要用于处理浅层和深层拷贝,在某些需要自定义数据结构的题目中能方便你进行对象拷贝,属于必须掌握的模块。主要只有两个函数:
copy:返回浅层拷贝。deepcopy:耗时大,返回深层拷贝对象。
16. os.path
在一些路径字符串分析题中非常有用,大部分情况下可以用re模块和str替代。
17. string/str
主要掌握str模块类的以下方法:
strip([chars]):返回原字符串的副本,移除其中的前导和末尾字符;常用于IOsplit(sep=None, maxsplit=-1):返回一个由字符串内单词组成的列表,常用于IOfind(sub, [start], [end]):返回子字符串 sub 在s[start:end]切片内被找到的最小索引count(sub, [start], [end]):反回子字符串 sub 在 [start, end] 范围内非重叠出现的次数。center(width, [fillchar]):返回长度为 width 的字符串,原字符串在其正中, 使用指定的 fillchar 填充两边的空位(优先填右)capitalize():返回将首字母大写、其余小写的原字符串副本index(sub, [start], [end]):类似find(),不推荐使用,因为找不到时会触发一个异常replace(old, new, [count]):替换子串,不过基本都由re.sub()替代该操作join(iterable):返回一个由 iterable 中的字符串拼接而成的字符串;常用于IOlower()/upper():返回一个副本,将所有字符转为小/大写lower()/isupper():判断是否全由小写字母/大写字母组成isdigit()/isdecimal()/isnumeric():判断是否全由数字字母组成【区别见下文】isalnum()/isalpha():判断是否全由字母和数字组成/判断是否全由字母组成translate(table):映射字符串,需要搭配str.maketrans(dict)一起用;eg:print("abc".translate(str.maketrans({"a": "1"})))将会输出1bctitle():转化为标题形式,仅用于一些针对性的题目
注意事项:
- 字符串类似一个
list,可以进行切片或使用s[::-1]的语法糖进行倒序,但不能s[i]="x"进行修改性赋值(请使用str.replace(...)或将其转为一个list) isdigit()/isdecimal()/isnumeric()的区别使用场景为:
| True | False | Error | |
|---|---|---|---|
| isdigit | Unicode数字,byte数字(单字节),全角数字(双字节),罗马数字 | 汉字数字 | / |
| isdecimal | Unicode数字,,全角数字(双字节) | 罗马数字,汉字数字 | / |
| isnumeric | Unicode数字,全角数字(双字节),罗马数字,汉字数字 | / | byte数字(单字节) |
18. base64
此模块提供了将二进制数据编码为可打印的 ASCII 字符以及将这些编码解码回二进制数据的函数,在某些数据分析题中很有用,但比较冷门,偶尔会遇到,如果掌握了可以节省大量的时间。
19. difflib
此模块提供用于比较序列的类和函数,在算法题中属于冷门模块,在一些用于比较字符串差异的题目中可以进行使用,例如比较 两个字符串序列的前后差异:
c = difflib.ndiff("abcd", "abde")
for i in c:
print(i)
TLE敏感操作
上文中提到了部分敏感操作,接下来继续总结一些:
x in obj要比obj.find(x)效率高,如str或list查找时。- 对
list进行扩增,以下三种方式的效率依次增高:for _ in range(j): li.append(x)<li[i:i+j] = [x]*j<li += [x]*j。 del x要比list.pop(index_x)效率高。list.reverse()要比list[::-1]效率高。[[0 for i in range(1000)] for j in range(1000)]要比[[0] * 1000 for j in range(1000)]效率高,但不推荐直接开一个特别大的数组,该操作本身非常耗时间。li += [1, 2, 3]要比li.extend([1, 2, 3])效率高,但在扩增的数据量较少时,候没有绝对优势。s.remove(x)要比s.pop(s.index(x))或del s[s.index(1)]有性能优势,如果非必要,请直接移除。相对的,还有以下性能比较:if x in s: s.remove(x)>del s[s.index(x)]>s.pop(s.index(x));总而言之,若对索引不感兴趣,尽量用in关键字做包含性查询、用del关键字移除对象。
转载:https://blog.csdn.net/Shenpibaipao/article/details/105873407