本文正在參加「Python主題月」,詳情查看 活動連接java
不少人對py的印象就是三方庫多,能直接調的函數多,這樣代碼總體顯得很短。python
本文盤點下那些好用的內置庫函數,用的好將會很是省事,配合leetcode食用更佳。git
這個模塊實現了特定目標的容器,以提供Python標準內建容器 dict,list , set, 和 tuple 的替代選擇。api
方便的計數器,注意首字母要大寫,是Counter。一般狀況下,若是咱們要對一組元素統計,得新建一個空對象,而後for循環遍歷元素,這就寫了至少5行了吧。使用Counter,輕鬆搞定。就像這樣數組
>>> import collections
>>> c = collections.Counter([3,1,2,3,1,4,4,4])
>>> c
Counter({4: 3, 3: 2, 1: 2, 2: 1})
>>> c[4] // 直接訪問4出現的次數
3
複製代碼
Counter可接受的參數能夠是iterable 或者mapping,例如:緩存
>>> from collections import Counter
>>> c = Counter('gallahad') //接受字符串,可迭代類型
>>> c
Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1})
>>> c = Counter({'red': 4, 'blue': 2} //接受一個映射
複製代碼
當訪問Counter中不存在的鍵時,會返回0,很是合理。markdown
Counter對象可使用字典的方法。還有most_common()方法,能夠直接指定求出現頻率最高的n個元素。數據結構
順帶一提,就是傳入的參數n大於了整個計數長度也不會報錯,app
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]
複製代碼
subtract(iterable or mapping) 一個計數器減去另一個,值還會出現負數和0函數
update(iterable or mapping),與上一個相反,是相加。
>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> d = Counter(a=1, b=2, c=3, d=4)
>>> c.subtract(d)
>>> c //c計數中減去d,c變了
Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
複製代碼
最離譜的是,還能夠直接用數學運算符,包括+ - | &。
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
c + d # 疊加
Counter({'a': 4, 'b': 3})
c - d # 相減
Counter({'a': 2})
c & d # 與,取小
Counter({'a': 1, 'b': 1})
c | d # 或: 取大,以上均過濾掉了值爲負數和0的項
Counter({'a': 3, 'b': 2})
複製代碼
leetcode實戰: 1207.獨一無二的出現次數
給你一個整數數組 arr
,請你幫忙統計數組中每一個數的出現次數。
若是每一個數的出現次數都是獨一無二的,就返回 true
;不然返回 false
。
解析:這題若是直接使用Counter來,有點不講武德。2行搞定。
class Solution:
def uniqueOccurrences(self, arr: List[int]) -> bool:
c=collections.Counter(arr)
return len(c)==len(set(c.values()))
複製代碼
雙端隊列,從雙端添加和刪除元素都是o(1)複雜度,比list快,list在頭部插入和刪除複雜度爲o(n)。
除了能使list的方法外,還有
appendleft(x) //添加x到左端
popleft()// 移除並返回左側第一個元素
rotate(n=1) //
...
向右循環移動 n 步。 若是 n 是負數,就向左循環。
若是deque不是空的,向右循環移動一步就等價於 d.appendleft(d.pop()) , 向左循環一步就等價於 d.append(d.popleft()) 。
...
複製代碼
maxlen定義了隊列最大長度,你能夠在初始化時使用參數指定最大長度,這樣隊列能夠造成一個自然的保存最近使用記錄的一個數據結構。
collections.deque
([iterable[, maxlen]])
>>> from collections import deque
>>> d = deque([1,2,3],4) //初始化
>>> d
deque([1, 2, 3], maxlen=4)
>>> d.appendleft(4) //左側加入
>>> d
deque([4, 1, 2, 3], maxlen=4)
>>> d[0]
4
>>> d.append(5) //右側加入,元素個數超過最大,左側元素自動排出了。
>>> d
deque([1, 2, 3, 5], maxlen=4)
>>> d.popleft() //左側排出元素
1
>>> d
deque([2, 3, 5], maxlen=4)
複製代碼
實戰:leetcode 3.無重複字符的最長字串
題目:給定一個字符串 s
,請你找出其中不含有重複字符的 最長子串 的長度。
解析:此題是經典滑動窗口問題。
可使用雙端隊列deque,模擬滑動窗口。當遇到隊列中已存在的字符時,從隊列左側排除元素,直到排出到與該字符相同的字符中止,記錄一下次時的隊列長度與max比較。該方法很是直觀,仍是很好理解的,不過速度並非最快的。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
queue = collections.deque()
if not s:return 0
res = 1
for s1 in s:
if s1 in queue:
res = max(res,len(queue)) //更新res
while True:
if queue.popleft() == s1: //左側出隊,直到無重複
break
queue.append(s1) //右側進隊
res = max(res,len(queue))
return res
複製代碼
deque很是實用的,還有102題二叉樹的層次遍歷,103二叉樹鋸齒層次遍歷 ,127單詞接龍,144,LRU緩存機制。 調函數就是這麼義正詞嚴。
使用collections.defaultdict
([default_factory[, ...]])
返回一種相似字典的對象,而且該對象的值爲指定類型。
一般就是設置爲defaultdict(int)或者defaultdict(list),前者默認爲0,後者爲[].
>>> s = 'mississippi'
>>> d = defaultdict(int) //等於指定默認鍵值爲0
>>> for k in s:
d[k]+=1 //省去判斷d中不存在鍵的過程
>>> d
defaultdict(<class 'int'>, {'m': 1, 'i': 4, 's': 4, 'p': 2})
複製代碼
有序字典,3.5之前,普通字典中鍵是無序的,在迭代時容易出問題。
不過3.6以後就有序了,跟js,java中的map相似了,彷佛用不上這個OrderedDict了
命名空間,命名元組,賦予每一個位置一個含義,提供可讀性和自文檔性。它們能夠用於任何普通元組,並添加了經過名字獲取值的能力,經過索引值也是能夠的。
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11,22)
>>> p
Point(x=11, y=22)
>>> p[0]+p[1]
33
>>> p.x+p.y //支持兩種訪問方式
33
複製代碼
好吧,有點像c語言中的結構體struct。
神級迭代器,你能想到的都有。
傳入一個iterable,一個算數操做,默認加法即累加器,返回一個迭代器。
>>> from itertools import accumulate
>>> accumulate([1,2,3,4]) //返回的是迭代器
<itertools.accumulate object at 0x000001DFD2BDFEC0>
>>> list(accumulate([1,2,3,4])) //累加,轉爲list
[1, 3, 6, 10]
>>> list(accumulate([1,3,2,4,6,5], max)) //當前最大值
[1, 3, 3, 4, 6, 6]
>>> import operator
>>> list(accumulate([1,3,2,4,6,5], operator.mul)) //乘法,求累積
[1, 3, 6, 24, 144, 720]
複製代碼
顧名思義,將多個可迭代的東西,有序地連起來。不用寫多個循環了。
>>> list(itertools.chain('abc','efg','hij'))
['a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j']
複製代碼
求組合的效果,跟真實的組合不一樣之處在於,值相同的元素會被視爲不一樣,所以會出現重複。
itertools.combinations
(iterable, r)
>>> list(itertools.combinations('ABCD',2)) // 返回的是元組
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
>>> list(itertools.combinations('dcba',2)) //出現順序跟序列順序有關
[('d', 'c'), ('d', 'b'), ('d', 'a'), ('c', 'b'), ('c', 'a'), ('b', 'a')]
>>> list(itertools.combinations(range(4),3))
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
複製代碼
順便提一個math.comb() 求組合的值,
>>> import math
>>> math.comb(10,2) // C(10,2)==10*9/2==45
45
複製代碼
全排列。使用itertools.``permutations
(iterable, r=None)
>>> from itertools import permutations
>>> list(permutations('DCBA', 2)) // 順序與參數序列有關
[('D', 'C'), ('D', 'B'), ('D', 'A'), ('C', 'D'), ('C', 'B'), ('C', 'A'), ('B', 'D'), ('B', 'C'), ('B', 'A'), ('A', 'D'), ('A', 'C'), ('A', 'B')]
>>> list(permutations(range(3))) //第二參數默認最長
[(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
複製代碼
實戰:leetcode 46全排列,39組合總數。
實際上直接調庫就失去了刷題自己的意義了,不推薦使用。
返回笛卡爾座標。
itertools.product
(*iterables, repeat=1)
>>> list(itertools.product('abc',range(2)))
[('a', 0), ('a', 1), ('b', 0), ('b', 1), ('c', 0), ('c', 1)]
複製代碼
實戰 : leetcode 17.電話號碼的字母組合
題:給定一個僅包含數字 2-9
的字符串,返回全部它能表示的字母組合。答案能夠按 任意順序 返回。
解法:其實就是拼音9建,按數字能打出的全部字母可能性. 組合問題,遞歸,回溯均可以。
使用itertools.product來作,可讀性不是很好,但很短。
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
b = {"2":"abc", "3":"def", "4":"ghi", "5":"jkl", "6":"mno", "7":"pqrs", "8":"tuv", "9":"wxyz"}
return [] if digits == "" else [ "".join(x) for x in itertools.product(*(b[d] for d in digits ))]
複製代碼
建立一個迭代器,從每一個可迭代對象中收集元素。若是可迭代對象的長度未對齊,將根據 fillvalue 填充缺失值。迭代持續到耗光最長的可迭代對象。
itertools.zip_longest
(*iterables, fillvalue=None)
>>> list(itertools.zip_longest('ABCD', 'xy', fillvalue='0'))//可用於補齊
[('A', 'x'), ('B', 'y'), ('C', '0'), ('D', '0')]
複製代碼
有個題用zip_longest賊好使的,一時找不到了,415題.字符串相加
zip()聚合來自每一個可迭代對象中的元素,返回迭代器。
當所輸入可迭代對象中最短的一個被耗盡時,迭代器將中止迭代。
>>> list(zip('ABCD', 'xy'))
[('A', 'x'), ('B', 'y')]
複製代碼
星號 * 對可迭代對象拆包,與ES6中的...剩餘運算符神似。
>>> a, *b, c = range(5) //介不是ES6的結構賦值嗎
>>> b
[1, 2, 3]
>>> list(zip(*(zip('ABCD', 'xy'))))//先壓,再解,再壓
[('A', 'B'), ('x', 'y')]
複製代碼
使用*能夠直接將zip對象拆開,全部的項做爲參數
這個東西很是實用,例如14.最長公共前綴
題目:編寫一個函數來查找字符串數組中的最長公共前綴。不存在公共前綴,返回 ""。
輸入:strs = ["flower","flow","flight"]
輸出:"fl"
複製代碼
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
out_str = ''
for i in zip(*strs)://解開數組,全部項爲參數再壓
if len(set(i)) == 1://等於1說明i中全部元素相同,即爲公共前綴
out_str += i[0]
else:
break
return out_str
複製代碼
還能夠用來旋轉矩陣:
>>> matric = [ [1,2,3],
[4,5,6],
[7,8,9]]
>>> list(zip(*matric[::-1])) //順時針
[(7, 4, 1),
(8, 5, 2),
(9, 6, 3)]
>>> list(zip(*matric))[::-1] //逆時針
[(3, 6, 9),
(2, 5, 8),
(1, 4, 7)]
複製代碼
自帶的數據結構堆
調用模式有點奇葩,我的以爲蠻怪的。
import heapq
h = [3,1,2,6,5,4]
>>> heapq.heapify(h)//原地修改l爲堆,啥也不返回
>>> h
[1, 3, 2, 6, 5, 4]
>>> heapq.heappop(h) // 取堆頂元素,而後自動調整
1
>>> h
[2, 3, 4, 6, 5]
>>> heapq.heappush(h,1) // 加入元素,調整
>>> h
[1, 3, 2, 6, 5, 4]
複製代碼
實戰:leetcode.215.尋找數組中的第k個最大元素
leetcode 劍指offer40,最小的k個數
分析:尋找最大的或者最小的k個數,均可以採用建堆的方法求解。
求最小的k個數須要大頂堆,最大的k個數須要小頂堆。
class Solution: //40題解法
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
if k == 0:
return list()
hp = [-x for x in arr[:k]]//取負數則求最大,建小頂堆,堆的大小取k
heapq.heapify(hp)
for i in range(k, len(arr)):
if hp[0] < -arr[i]: //與堆頂元素比較,若是大於堆頂元素,則入堆
heapq.heappop(hp)
heapq.heappush(hp, -arr[i]) //排出最小
ans = [-x for x in hp] //獲得最大的k個數,取負數得最小
return ans
//來源:力扣(LeetCode)
複製代碼
畢生所學都在這裏了,點個贊吧,球球了。