1. 程式人生 > 其它 >array python 交集_一些刷題常用的 python 技巧

array python 交集_一些刷題常用的 python 技巧

技術標籤:array python 交集

Python 越來越多地成為大家刷題的主流語言,主要原因是它的語法非常簡潔明瞭。因此我們能節省更多的時間,來關注演算法和資料結構本身。

而用好 Python 自身獨有的一些語法特性,不僅能更節省時間,也能讓程式碼看起來更加優雅。這裡我總結了一些我自己刷題過程中用到的一些常用的功能。以下以 python3 為例, python2 略有差異。

List

Python 的列表 List 基本就是其它語言的 Array.

Initialization 初始化

List 的初始化一般用 List comprehension,往往能一行解決問題

# 1d array
l = [0 for _ in range(len(array)]
# or
l = [0] * len(array)

# 2d
l = [[0] for i in range(cols) for j in range(rows)]

Start from the behind

你可以輕鬆從後往前訪問:

lastElement = l[-1]

lastTwo = l[-2:]

for i in range(0, -10, -1)
# 0, -1, -2, -3, -4, -5, -6, -7, -8, -9

copy 複製

shallow copy 淺拷貝

l2 = l1[:]
# or
l2 = l1.copy()

淺複製的問題在於,如果 l1 內部還有 list,那麼這種巢狀的索引不能被複制,比如:

a = [1, 2, [3, 4]]
b = a[:]
a[2].append(5)
print(b)
# [1, 2, [3, 4, 5]]

deep copy 深拷貝

所以如果要做深拷貝,要節制自帶庫 copy

import copy

copy.deepcopy()

enumerate 列舉

當我們需要列舉一個數組並同時獲得值與 index 的時候可以使用:

l = ["a", "b", "c"]

for i, v in enumerate(l):
    print(i, v)
# 0 a
# 1 b
# 2 c

zip

zip 本意就是拉鍊,可以想象成將兩個陣列像拉鍊一樣挨個聚合:

>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> zipped = zip(x, y)
>>> list(zipped)
[(1, 4), (2, 5), (3, 6)]

reduce

reduce 可以分別對相鄰元素使用同一種計算規則,同時每一步結果作為下一步的引數,很典型的函數語言程式設計用法。

# importing functools for reduce()
import functools
# initializing list
lis = [ 1, 3, 5, 6, 2, ]

# using reduce to compute sum of list
print ("The sum of the list elements is : ",end="")
print (functools.reduce(lambda a,b : a+b,lis))

# The sum of the list elements is : 17

map

可以將引數一一對映來計算, 比如

date = "2019-8-15"
Y, M, D = map(int, date.split('-'))
# Y = 2019, M = 8, D = 15

deque

list 刪除末尾的操作是O(1)的,但是刪除頭操作就是O(n),這時候我們就需要一個雙端佇列 deque。首尾的常規操作為:

  • append,新增到末尾
  • appendleft, 新增到開頭
  • pop, 剔除末尾
  • popleft,移除開頭

sorted

list 自身有自帶的 sort(), 但是它不返回新的 list. sorted 能返回一個新的 list, 並且支援傳入引數reverse

比如我們有一個 tuple 的陣列,我們想按照 tuple 的第一個元素進行排序:

l1 = [(1,2), (0,1), (3,10) ]

l2 = sorted(l1, key=lambda x: x[0])

# l2 = [(0, 1), (1, 2), (3, 10)]

這裡的 key 允許傳入一個自定義引數,也可以用自帶函式進行比較,比如在一個 string 數組裡只想比較小寫,可以傳入key=str.lower

l1 = ["banana","APPLE", "Watermelon"]
l2 = sorted(l1, key=str.lower)
print(l2)

# ['APPLE', 'banana', 'Watermelon']

lambda

你注意到我們在上面使用了 lambda 來定義一個匿名函式,十分方便。如果你熟悉其它語言類似 JS 的話,可以把它理解成一個 callback 函式,引數名一一對應就行。

cmp_to_key

在 python3 中,sorted 函式取消了自帶的cmp函式,需要藉助functools 庫中的 cmp_to_key來做比較。
比如如果要按照陣列元素的絕對值來排序:

from functools import cmp_to_key
def absSort(arr):
    newarr = sorted(arr, key = cmp_to_key(sortfunc))
    return newarr
def sortfunc(a, b):
    if abs(a) < abs(b):
      return -1
    elif abs(a) > abs(b):
      return 1
    else:
      return a - b

set

set 的查詢操作複雜度為O(1),有時候可以替代dict 來儲存中間過程。

  • add : set 的新增是 add 不是append
  • remove vs discard: 都是刪除操作,區別在於remove不存在的元素會報錯,discard不會。
  • union, intersection: 快速獲得並集和交集,方便一些去重操作。

dict

字典,相當於其它語言中的map, hashtable, hashmap之類的,讀取操作也是O(1) 複雜度

keys(), values(), items()

這三個方法可以分別獲得key, value, {key: value}的陣列。

setdefault

這個函式經常在初始化字典時候使用,如果某個key在字典中存在,返回它的value, 否則返回你給的 default 值。比如在建一個 trie 樹的時候

node = self.root
for char in word:
    node = node.setdefault(char, {})

OrderedDict

OrderedDict 能記錄你 key 和 value 插入的順序,底層其實是一個雙向連結串列加雜湊表的實現。我們甚至可以使用move_to_end這樣的函式:

>>> d = OrderedDict.fromkeys('abcde')
>>> d.move_to_end('b')
>>> ''.join(d.keys())
'acdeb'
# 放開頭
>>> d.move_to_end('b', last=False)
>>> ''.join(d.keys())
'bacde'

defaultdict

defaultdict可以很好地來解決一些初始化的問題,比如 value 是一個 list,每次需要判斷 key 是否存在的情況。這時我們可以直接定義

d = defaultdict(list)

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
for k, v in s:
     d[k].append(v)
sorted(d.items())
# [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

heapq

heapq 就是 python 的 priority queue,heapq[0]即為堆頂元素。

heapq 的實現是小頂堆,如果需要一個大頂堆,常規的一個做法是把值取負存入,取出時再反轉。
以下是藉助 heapq 來實現 heapsort 的例子:

>>> def heapsort(iterable):
...     h = []
...     for value in iterable:
...         heappush(h, value)
...     return [heappop(h) for i in range(len(h))]
...
>>> heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

bisect

python 自帶二分查詢的庫,在一些不要求實現 binary search,但是藉助它能加速的場景下可以直接使用。

bisect.bisect(a, x, lo=0, hi=len(a))
這裡的引數分別為 陣列,要查詢的數,範圍起始點,範圍結束點

相似函式還有

  • bisect.bisect_left
  • bisect.bisect_right
    分別返回可以插入 x 的最左和最右 index

Counter

Counter 接受的引數可以是一個 string, 或者一個 list, mapping

>>> c = Counter()                           # a new, empty counter
>>> c = Counter('gallahad')                 # a new counter from an iterable
>>> c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
>>> c = Counter(cats=4, dogs=8)             # a new counter from keyword args
  • most_common(n)
    可以得到出現次數最多的 n 個數:
>>> Counter('abracadabra').most_common(3)  # doctest: +SKIP
[('a', 5), ('r', 2), ('b', 2)]

strings

ord, char

ord 返回單個字元的 unicode:

>>> ord('a')
97

char 則是反向操作:

>>> chr(100)
'd'

strip

移除 string 前後的字串,預設來移除空格,但是也可以給一個字串,然後會移除含有這個字串的部分:

>>> '   spacious   '.strip()
'spacious'
>>> 'www.example.com'.strip('cmowz.')
'example'

split

按照某個字串來切分,返回一個 list, 可以傳入一個引數maxsplit來限定分離數。

>>> '1,2,3'.split(',')
['1', '2', '3']
>>> '1,2,3'.split(',', maxsplit=1)
['1', '2,3']
>>> '1,2,,3,'.split(',')
['1', '2', '', '3', '']

int/ float

最大, 最小 number

有時候初始化我們需要設定 Math.max()Math.min(), 在 python 中分別以 float('inf')float('-inf')表示

我們也可以這麼做:

import sys

#maxint
Max = sys.maxint

除法

在 python3 中, / 會保留浮點,相當於 float 相除,如果需要做到像 pyhton2 中的 int 相除,需要 //

>>> 3 / 2
1.5
>>> 3 // 2
1

次方

在 python 中為 **:

>>> 2 ** 10
1024

conditions

在 python 的三項表示式(ternary operation) 與其它語言不太一樣:

res = a if condition else b

它表示如果 condition 滿足,那麼 res = a, 不然 res = b,在類 c 的語言裡即為:

res = condition ? a : b;

any, all

any(), all()很好理解,就是字面意思,即引數中任何一個為 true 或者全部為 true 則返回 true。經常可以秀一些騷操作:
比如 36. Valid Sudoku 這題:

class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        row = [[x for x in y if x != '.'] for y in board]
        col = [[x for x in y if x != '.'] for y in zip(*board)]
        pal = [[board[i+m][j+n] for m in range(3) for n in range(3) if board[i+m][j+n] != '.'] for i in (0, 3, 6) for j in (0, 3, 6)]
        return all(len(set(x)) == len(x) for x in (*row, *col, *pal))

itertools

這是 python 自帶的迭代器庫,有很多實用的、與遍歷、迭代相關的函式。

permutations 排列

permutations('ABCD', 2)
# AB AC AD BA BC BD CA CB CD DA DB DC

combinations 組合

combinations('ABCD', 2)
# AB AC AD BC BD CD

groupby 合併

https://leetcode.com/problems/swap-for-longest-repeated-character-substring/discuss/355852/Python-Groupby/322898

[k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
[list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D

functools

這個庫裡有很多高階函式,包括前面介紹到的cmp_to_key 以及 reduce,但是比較逆天的有 lru_cache,即 least recently used cache. 這個 LRU Cache是一個常見的面試題,通常用 hashmap 和雙向連結串列來實現,python 居然直接內建了。

用法即直接作為 decorator 裝飾在要 cache 的函式上,以變數值為 key 儲存,當反覆呼叫時直接返回計算過的值,例子如下:

lru_cache

https://leetcode.com/problems/stone-game-ii/discuss/345230/Python-DP-Solution

def stoneGameII(self, A: List[int]) -> int:
      N = len(A)
      for i in range(N - 2, -1, -1):
          A[i] += A[i + 1]
      from functools import lru_cache
      @lru_cache(None)
      def dp(i, m):
          if i + 2 * m >= N: return A[i]
          return A[i] - min(dp(i + x, max(m, x)) for x in range(1, 2 * m + 1))
      return dp(0, 1)

resource

這是一個大神用各種 Python trick 解題的 repo,可供娛樂:

https://github.com/cy69855522/Shortest-LeetCode-Python-Solutions

當然 Leetcode 討論區還會經常見到 StefanPochmann 或者 lee215這樣的大神 Po 一些很秀技的 python 程式碼,都是學習範本