1、求解列表最大值及其下标:
max(zip(nums, range(len(nums))))
2、反转列表:
reversed(range(n))
下面的写法与上面的写法等价
range(n, -1, -1)
下面的写法也能实现列表反转, 但是a[3:-1:-1]不能实现边截取边反转,只能通过list(reversed(a[0:4]))实现
a[::-1]
3、二维列表的截取:
[[a[i][j] for j in range(n // 2)] for i in range(n //2)]
跟matlab不同的是,下面写法无法对列进行截取,因为a[:n // 2]本身是一个二维列表
a[:n//2][:n//2]
4、堆的使用,如果使用大顶堆,需要对数值取反:
import queue
q = queue.PriorityQueue()
q.put(num) #放置元素
q.qsize() #获取队列长度
q.get() #取出堆顶元素
q.queue[0] #获取堆顶元素
该模块(queue.PriorityQueue)是从下面的模块(heap)总封装成的,具有线程安全的特点
import heapq
heapq.heapify(nums) #堆排序数组
heapq.heappush(heap, num) #放入元素
heapq.heappop(heap) #取出堆顶元素
nums[0] #获取堆顶元素
5、排序,自定义排序比较函数
from functools import cmp_to_key
def compare(x, y):
return int(y+x) - int(x+y)
nums = sorted(map(str, nums), key=cmp_to_key(compare))
6、 if a: 既会判断 a 是否非None, 是否列表非空,是否字符串不为空串,是否不为0,相当于if bool(a):
7、使用迭代器中序遍历二叉树:
def inOrder(p):
if not p: return
yield from inOrder(p.left)
yield p.val
yield from inOrder(p.right)
print(list(inOrder(root)))
但是效率不如直接添加到数组,见二叉搜索树最近节点查询
8、二分查找
import bisect
bisect.bisect([2,3,5,6,7],5) #3
bisect.bisect_left([2,3,5,6,7], 5) #3
bisect.bisect_right([2,3,5,6,7], 5) #2
返回的插入点 i 可以将数组 a 分成两部分。左侧是 all(val < x for val in a[lo:i])
,右侧是 all(val >= x for val in a[i:hi])
参考资料:8.6. bisect — 数组二分查找算法 — Python 3.6.15 文档
【Python】详解 bisect 模块_闻韶-优快云博客_bisect.bisect_left
此外,该函数不仅可以对固定数组进行二分查找,还可以根据输入求出表达式的值,例如:有序数组中的缺失元素
class Solution:
def missingElement(self, nums: List[int], k: int) -> int:
self.__class__.__getitem__ = lambda self, mid: nums[mid] - (nums[0] + mid) >= k
l = bisect.bisect_left(self, True, 0, len(nums))
return nums[l - 1] + k - (nums[l - 1] - (nums[0] + (l - 1)))
Python 3.10 支持通过 key
自定义二分规则: 例如:最小化两个数组中的最大值
class Solution:
def minimizeSet(self, d1: int, d2: int, uniqueCnt1: int, uniqueCnt2: int) -> int:
lcm = math.lcm(d1, d2)
def check(x: int) -> bool:
left1 = max(uniqueCnt1 - x // d2 + x // lcm, 0)
left2 = max(uniqueCnt2 - x // d1 + x // lcm, 0)
common = x - x // d1 - x // d2 + x // lcm
return common >= left1 + left2
return bisect_left(range((uniqueCnt1 + uniqueCnt2) * 2 - 1), True, key=check)
9、有序字典
from sortedcontainers import SortedDict as SD
sd = SortedDict({1: 3, 3: 1, 2: 2}) #SortedDict({1: 3, 2: 2, 3: 1})
idx = sd.bisect_right(2) #2
idx = sd.bisect_left(2) #1
sd.values()[idx] #2
10、有序列表
from sortedcontainers import SortedList
s = SortedList([])
s.add(("ds", 2))
s.add(("ad", 3))
print(s) #SortedList([('ad', 3), ('ds', 2)])
11、默认词典:
from collections import defaultdict
m = defaultdict(int)
m[0] += 1 #defaultdict(<class 'int'>, {0: 1})
12、 计数:
import collections
a = [1,2,3,4,2,4,5,2,3]
m = collections.Counter(a) #Counter({2: 3, 3: 2, 4: 2, 1: 1, 5: 1})
m.count(4) #2
13、lru缓存
from functools import lru_cache
@lru_cache()
def f(n):
if n <= 1: return n
return f(n - 1) + f(n - 2)
f(100) #354224848179261915075
14、按照频率将数组升序排序
sorted(nums, key = lru_cache(None)( lambda n: (nums.count(n), -n) ))
sum(iter(v for _,_,v in sorted((v,-k,[k]*v) for k,v in Counter(nums).items())),[])
15、求取前缀和
list(itertools.accumulate([1,2,3,4,5], initial=0)) #[0, 1, 3, 6, 10, 15]
16、找到二进制1的个数以及二进制的长度
print((n:=2).bit_count())
print((n:=2).bit_length())
17、求排列组合及数目
print(list(itertools.combinations([1,2,3,4], 2)))
#[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
print(math.comb(4, 2)) # 6
print(list(itertools.permutations([1,2,3], 2)))
#[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
print(math.perm(3, 2)) #6
print(math.factorial(6)) #720
18、求最大公约数和最小公倍数
math.gcd(4,6) #2
math.lcm(4, 6, 8) #24
19、reduce函数
reduce(lambda x,y: x*y, [1,2,3,4]) #24
20、pairwise函数
pairwise([1,2,3,4]) #[(1,2),(2,3),(3,4)]
21、取余定律
- 加法:
- 减法:
- 乘法:
- 幂运算:
除法取余涉及到逆元,可直接使用python自带的库
pow(a, -1, mod)
如果模数不是质数,需要拆成多个质数组合,使用中国剩余定理
排列组合逆元:
class Permutation:
"""排列组合计算器"""
def __init__(self, mod: int = 10 ** 9 + 7):
self._mod = mod
self._size = 0
self._cache_factorial = [1] # 缓存阶乘
self._cache_factorial_inv = [1] # 缓存阶乘的乘法逆元
def factorial(self, n: int) -> int:
"""计算阶乘:n!"""
while self._size <= n:
self._size += 1
self._cache_factorial.append((self._cache_factorial[-1] * self._size) % self._mod)
self._cache_factorial_inv.append(pow(self._cache_factorial[-1], self._mod - 2, self._mod))
return self._cache_factorial[n]
def arrange(self, n: int, m: int) -> int:
"""计算排列数:A(n,m) (n>=m)"""
return (self.factorial(n) * self._cache_factorial_inv[n - m]) % self._mod
def comb(self, n: int, m: int) -> int:
"""计算组合数:C(n,m) (n>=m)"""
return (self.arrange(n, m) * self._cache_factorial_inv[m]) % self._mod
模数排列组合也可以使用卢卡斯定理,对于判断操作后字符串中的数字是否相等 II,解法如下:
# lucas定理
def comb_mod(n, k, p):
res = 1
while n > 0 or k > 0:
ni = n % p
ki = k % p
if ki > ni:
return 0
res = res * comb(ni,ki) % p
n //= p
k //= p
return res
class Solution:
def hasSameDigits(self, s: str) -> bool:
'''
左右两个数都是杨辉三角,系数为C(L,i)
'''
l = 0
r = 0
n = len(s)
# 中国剩余定理
def CRT(i,num):
return (comb_mod(n-2,i,2) * 5 + comb_mod(n-2,i,5) * 2) * num % 10
for i in range(n-1):
l += CRT(i,int(s[i]))
l %= 10
r += CRT(i,int(s[i+1]))
r %= 10
return l == r
模数不是质数,也可以把每个数中的因子2和5单独提取出来,单独统计因子个数,代码如下:
MOD = 10
MX = 100_000
f = [0] * (MX + 1)
inv_f = [0] * (MX + 1)
p2 = [0] * (MX + 1)
p5 = [0] * (MX + 1)
f[0], inv_f[0] = 1, 1
for i in range(1, MX + 1):
x = i
# 计算 2 的幂次
e2 = (x & -x).bit_length() - 1
x >>= e2
# 计算 5 的幂次
e5 = 0
while x % 5 == 0:
e5 += 1
x //= 5
f[i] = f[i - 1] * x % MOD
p2[i] = p2[i - 1] + e2
p5[i] = p5[i - 1] + e5
#也可以 inv_f[i] = (inv_f[i - 1] * pow(x, -1, MOD)) % MOD
inv_f[MX] = pow(f[MX], 3, MOD) # 欧拉定理求逆元
for i in range(MX, 0, -1):
x = i
x >>= (x & -x).bit_length() - 1
while x % 5 == 0:
x //= 5
inv_f[i - 1] = inv_f[i] * x % MOD
def comb(n: int, k: int) -> int:
return f[n] * inv_f[k] * inv_f[n - k] * \
pow(2, p2[n] - p2[k] - p2[n - k], MOD) * \
pow(5, p5[n] - p5[k] - p5[n - k], MOD) % MOD
class Solution:
def solve(self, s: List[int]) -> int:
return sum(comb(len(s) - 1, i) * x for i, x in enumerate(s)) % MOD
def hasSameDigits(self, s: str) -> bool:
s = list(map(int, s))
return self.solve(s[:-1]) == self.solve(s[1:])
参考资料:
Python SortedContainers Module 对字典排序_阿茂丶-优快云博客_sortedcontainers
Python| itertools之pairwise:获取连续的重叠对_lovetaozibaby的博客-优快云博客_pairwise python排列组合计算器(包含乘法逆元)