[Python][刷題常用模塊]用Python刷題,這一篇就夠了

引言

最近在復刷LeetCode,某種意義上要做題做的快對STL保持熟悉度是蠻重要的,至少在求和、排序、查找時就不用重複敲代碼了。於是,整理了部分常用python算術/數據結構/數理模塊,以及相應的對TLE敏感的操作,希望能幫助到其它人。

python內建函數

  • format():格式化輸出函數(在控制輸出精度和空格補齊等問題中很好用)
  • round(x):四捨五入
  • cmp(x, y):比較2個對象,如果x<yx < y 返回$ -1,, 如果x==y$返回00, 如果x>yx > y返回11
  • abs(x)/max()/min():絕對值/最大值/最小值
  • len():返回對象的長度,如列表、字典等
  • range(start=0, stop, step=1]):返回一個可迭代對象,常用於for循環
  • sum(iterable): 求和函數
  • pow(x, y, [z]):求冪函數xyx^y,運算完畢可以順帶對z取模;大數取模問題可以直接AC
  • sorted(iterable, key, reverse):採用Timsort的穩定排序算法,默認升序;該函數太重要了,請多寫寫代碼研究一下它的各個參數
  • isinstance(obj, type):判斷類型
  • all(iterable)/any(iterable):迭代與操作/迭代或操作(01None均等價於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+2j
  • divmod():函數把除數和餘數運算結果結合起來,返回一個包含商和餘數的元組(a // b, a % b)
  • eval(expression, [globals, locals]):執行一個字符串表達式,並返回表達式的值,eg:eval('pow(2, 2)')=4=4;在某些字符串解析題中非常好用,詳細可見[>此處<],(https://www.runoob.com/python/python-func-eval.html)
  • map(function, iterable...):映射函數,需要注意的是在Python3中返回一個迭代對象而不再是一個列表
  • filter(function, iterable):過濾函數
  • reduce(function, iterable, [initializer]):累積函數,現在被歸類到functools模塊中
  • zip(iterable, ...):將對象中對應的元素打包成一個個元組,常用於並聯取值,詳見下文的【注意事項】
  • hash(obj):返回哈希碼,常用於對象比較或將其轉化爲唯一的索引(不過更推薦使用id()完成該需求)
  • id():返回對象的唯一標識符,和hash()類似,但更魯棒更快且可以對listdef等對象求id
  • enumerate():將一個可遍歷的數據對象組合爲一個索引序列,eg:for i, v in enumerate(list_a):

>參考資料:完整列表<


注意事項

  1. 標準輸出函數print(*objects, sep=' ', end='\n')可以通過設置seq標誌位來設定間隔字符、設置end來設定結尾字符,常用於進行靈活的輸出。對列表輸出時,也常用' '.join(result_list)來快速輸出一個串,而不用挨個遍歷。
  2. 需要注意的是,若從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語言差異很大,請留心
  1. mapfilterreduce等函數式編程函數很重要,能夠讓你少敲很多代碼,特別是filter在篩選題中有高的實用性。
  2. 特別的,float()可用來構造無限值,如float('inf')
  3. yield關鍵字也很重要,可用來創建生成器,在數列生成、斐波那契查找等用處很大,可以極大的節省開銷。>舉例一則<>教程指南<。需要注意的是,當迭代器函數執行結束時,將自動拋出StopIteration異常,僅在 for 循環裏,無需處理StopIteration異常,循環會正常結束,否則需要使用except關鍵字捕獲。
  4. 有些時候tryexcept Exception as efinally等語句可以直接避免在函數體裏進行空值檢定,大大減少敲鍵盤的時間開銷:>舉例一則<
  5. 善用set()來進行列表去重。
  6. format()函數能方便你的格式化輸出,如小數精度控制問題,請考慮>進行學習<
  7. input()raw_input()的區別在於對於python的兩個版本(2/3)表現不一致,python 3請使用前者,接收到的數據默認爲str
  8. 對於非對象類(如list)變量,需要用global關鍵詞在函數內使用全局變量。
  9. del關鍵詞會比list.pop(index)擁有更高的效率,屬於TLE敏感的操作。
  10. list[::-1]語法糖可以快速對列表進行倒序,在字符串倒序等問題中有奇效;但list.reverse()更高效,屬於TLE敏感的操作。(另外需要注意:後者是原地倒序)
  11. 在python 3中,zip()返回一個可迭代對象,需要手動list()以進行其它列表操作。
  12. 求均值、中位數、衆數的API在statistics模塊中;求衆數可以調用collections.Counter來實現。
  13. python默認的遞歸棧很有限,有時候會出現C語言能過而python不能過的情況,請>參考此處<解決這個問題——maximum recursion depth exceeded in comparison

算術模塊

1. math

常量:

  • pi:圓周率 (3.141592653589793)
  • inf:無限大
  • nan:非數字(Not A Number)
  • e:自然數
  • tau:圓周率的兩倍,用於計算弧度和角度的換算。( 2π×2π \times弧度=360°=360°)

常用方法:

  • floor(x):向下取整,eg:floor(35.7)=35floor(35.7)=35
  • ceil(x):向上取整,eg:floor(35.1)=36floor(35.1)=36
  • trunc(x):直接去除數字的小數部分,作用等同floor
  • gcd(a, b):求最大公約數,返回值默認與bb同號(b非0時);任一數爲00時返回00
  • pow(x, y):求冪( xyx^y),返回浮點數,eg:math.pow(2,3)=8.0math.pow(2, 3)= 8.0
  • log(x, y):求對數logyxlog_yx,返回浮點數,eg:math.log(8,2)=3.0math.log(8, 2) = 3.0
  • log2(x)/log10(x)/log1p(x):以22/1010爲底的對數;求自然對數ln(x+1)ln(x+1)
  • radians:將角度轉換爲弧度
  • sin/sinh:正弦
  • cos/cosh:餘弦
  • tan/tanh:正切
  • sqrt(x):平方根
  • modf(x):返回浮點數xx的小數和整數部分,eg:modf(32.5)=(0.5,32)modf(32.5)=(0.5, 32)
  • exp(x):指數函數exe^x,需要注意的是math.pow(math.e, x)精度會更高
  • isnan/isinf/isfinite:常量檢測函數,isfinite當檢測數爲infnan時返回False

注意事項

  1. math.fabs()和內建函數中的abs()相比,後者支持複數運算。複數的絕對值計算:a±bj=a2+b2|a±bj|=\sqrt{a^2+b^2}
  2. divmod(a, b)math.modf(x)相比,前者返回元組(a // b, a % b),後者拆分小數和整數部分;前者支持複數運算。
  3. math.pow()和內建函數中的pow()相比,前者運算爲浮點型,後者會保留整形(還可以順帶取模)
  4. fractions.gcd()在Python 3後已被math.gcd()取代。

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

二分查詢算法模塊,時間複雜度O(n)=lognO(n)=log_n。常用於有序序列(升序)的插入和查找。默認使用bisect_right()insort_right()

  • bisect_left(a, x, lo=None, hi=None)/bisect_right():在有序列表的[lo,hi)[lo, hi)a中查找值x並返回其索引,有左向和右向之分,分別當命中時返回左/右一位的索引,即bisect_left -> all e in a[i:] have e >= xbisect_right -> all e in a[i:] have e > x
  • insort_left(a, x, lo=None, hi=None)/insort_right():在有序列表的[lo,hi)[lo, hi)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):求最大公約數,返回值默認與bb同號(b非0時);任一數爲00時返回00

注意事項:

  1. 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.dequequeue.deque更加強大;後者是對前者的封裝,作爲模塊內建對象存在,而前者這是一個類。後者擁有dequeueenqueue等標準隊列操作,但個人更推薦使用前者而不是後者。

函數式編程/編程風格優化

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 15
  • chain:創建一個迭代器,它首先返回第一個可迭代對象中所有元素,接着返回下一個可迭代對象中所有元素,直到耗盡所有可迭代對象中的元素,eg:chain('ABC', 'DEF') --> A B C D E F
  • compress(data, selectors):返回 data 中經 selectors 真值測試爲 True 的元素,eg:compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
  • dropwhile:從首次真值測試失敗開始,eg:dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
  • takewhile:直到首次真值測試失敗結束,eg:takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
  • filterfalse(predicate, iterable):返回iterablepredicateFalse的元素,eg:`filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8
  • groupby(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 G
  • starmap(function, iterable):星映射迭代器,eg:starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000
  • tee(iterable, n):拆分一個迭代器爲nn
  • 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 DD
  • permutations:連續返回由 iterable 元素生成長度爲 r 的排列,和combinations有點類似,即返回組合排列解,eg:permutations('ABCD, 2') --> AB AC AD BA BC BD CA CB CD DA DB DC
  • combinations:返回由輸入iterable中元素組成長度爲rr的子序列,eg:combinations('ABCD', 2) --> AB AC AD BC BD CD

注意事項

  1. accumulate可通過給定一個func來自定義累加過程,例如給定max作爲累加器,則統計的是至今爲止最大的數,在一些題目中相當好用。
  2. combinations本質上就是就是計算組合數,在一些數學題中相當好用,例如print(len(list(itertools.combinations('ABCD', 2))))可以直接得到C42=6C_4^2=6permutations則是返回A22C42A_2^2C_4^2

專業導向

專業導向的模塊除了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和其他二進制數據類型的轉換。常用於處理二進制或字符串題。

>簡易入門<
format-characters

14.re

在這些專業導向的模塊中,正則模塊則是最重要的模塊,能處理大量字符串相關的題目,需要額外學習正則表達式,此處不再贅述,屬於必須掌握的模塊。請參考>本文檔<進行學習。

15. copy

主要用於處理淺層和深層拷貝,在某些需要自定義數據結構的題目中能方便你進行對象拷貝,屬於必須掌握的模塊。主要只有兩個函數:

  • copy:返回淺層拷貝。
  • deepcopy:耗時大,返回深層拷貝對象

16. os.path

在一些路徑字符串分析題中非常有用,大部分情況下可以用re模塊和str替代。

17. string/str

主要掌握str模塊類的以下方法:

  • strip([chars]):返回原字符串的副本,移除其中的前導和末尾字符;常用於IO
  • split(sep=None, maxsplit=-1):返回一個由字符串內單詞組成的列表,常用於IO
  • find(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 中的字符串拼接而成的字符串;常用於IO
  • lower()/upper():返回一個副本,將所有字符轉爲小/大寫
  • lower()/isupper():判斷是否全由小寫字母/大寫字母組成
  • isdigit()/isdecimal()/isnumeric():判斷是否全由數字字母組成【區別見下文】
  • isalnum()/isalpha():判斷是否全由字母和數字組成/判斷是否全由字母組成
  • translate(table):映射字符串,需要搭配str.maketrans(dict)一起用;eg: print("abc".translate(str.maketrans({"a": "1"})))將會輸出1bc
  • title():轉化爲標題形式,僅用於一些針對性的題目

注意事項:

  1. 字符串類似一個list,可以進行切片或使用s[::-1]的語法糖進行倒序,但不能s[i]="x"進行修改性賦值(請使用str.replace(...)或將其轉爲一個list)
  2. 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敏感操作

上文中提到了部分敏感操作,接下來繼續總結一些:

  1. x in obj要比obj.find(x)效率高,如strlist查找時。
  2. list進行擴增,以下三種方式的效率依次增高:for _ in range(j): li.append(x)<li[i:i+j] = [x]*j<li += [x]*j
  3. del x要比list.pop(index_x)效率高。
  4. list.reverse()要比list[::-1]效率高。
  5. [[0 for i in range(1000)] for j in range(1000)]要比[[0] * 1000 for j in range(1000)]效率高,但不推薦直接開一個特別大的數組,該操作本身非常耗時間。
  6. li += [1, 2, 3]要比li.extend([1, 2, 3])效率高,但在擴增的數據量較少時,候沒有絕對優勢。
  7. 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關鍵字移除對象。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章