对竞赛中常用得标准库进行解析和给出代码模板
题型
1.思维题/杂题:数学公式,分析题意,找规律
2.BFS/DFS:广搜(递归实现),深搜(deque实现)
3.简单数论:模,素数(只需要判断到 int(sqrt(n))+1),埃式筛,gcd,lcm,快速幂(位运算移位操作),大数分解(分解为质数的乘积)
4.简单图论:最短路(一对多(Dijstra,临接表,矩阵实现),多对多(Floyd,矩阵实现)),最小生成树(并查集实现Kruskal算法,Prim算法),Floyd,DIjstra,Bellman-Ford,SPFA
5.简单字符串处理:最好转为列表操作
6.DP:线性DP,最长公共子序列,0/1背包问题,最长连续字符串,最大递增子串,数位DP,树形DP,区间DP,状态压缩DP(借用位运算)
7.基本算法:二分,贪心,组合,排列,前缀和,差分,倍增
8.基本数据结构:队列,集合,字典,字符串,列表,栈,树
9.高级数据结构:并查集,带权并查集,树状数组,线段树
10.字符串:KMP算法,哈希算法,回文字符串
11.常用模块:math,datetime,sys中的设置最大递归深(sys.setrecursionlimit(3000000)),collections.deque(队列),itertools.combinations(list,n)(组合),itertools.permutations(list,n)(排列) heapq(小顶堆)bisect(二分)
1.functools
1.1 cmp_to_key
将旧风格的比较函数转换为key函数。
-1 不变 1 交换位置
import functools
x=[1,3,2,4,5]
def cmp_rise(a,b):
'''
升序排序:
当前面的参数a小于后面的参数b返回-1,-1代表保持不变,
当前面的的参数a大于等于后面的参数b返回1,1代表交换顺序。
因此保证了前面的数子小于后面的数字,是升序排序。
'''
if a <b:
return -1
else:
return 1
def cmp_decline(a,b):
'''
降序排序:
当前面的参数a小于后面的参数b返回1,1代表交换顺序,
当前面的的参数a大于等于后面的参数b返回-1,-1代表保持不变。
因此保证了前面的数子大于后面的数字,是降序排序。
'''
if a <b:
return 1
else:
return -1
x_sorted_by_rise=sorted(x,key=functools.cmp_to_key(cmp_rise))
x_sorted_by_decline=sorted(x,key=functools.cmp_to_key(cmp_decline))
print(x) # 输出结果:[1, 3, 2, 4, 5]
print(x_sorted_by_rise) # 输出结果:[1, 2, 3, 4, 5]
print(x_sorted_by_decline) # 输出结果:[5, 4, 3, 2, 1]
1.2 lru_cache(记忆化存储,加快递归速度)
允许我们将一个函数的返回值快速地缓存或取消缓存。
该装饰器用于缓存函数的调用结果,对于需要多次调用的函数,而且每次调用参数都相同,则可以用该装饰器缓存调用结果,从而加快程序运行。
该装饰器会将不同的调用结果缓存在内存中,因此需要注意内存占用问题。
from functools import lru_cache
@lru_cache(maxsize=30) # maxsize参数告诉lru_cache缓存最近多少个返回值
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
print([fib(n) for n in range(10)])
fib.cache_clear() # 清空缓存
2.collections
2.1 deque
双端队列,用于实现单调队列和BFS搜索
from collections import deque
q = deque(['a', 'b', 'c'], maxlen=10)
# 从右边添加一个元素
q.append('d')
print(q) # deque(['a', 'b', 'c', 'd'], maxlen=10)
# 从左边删除一个元素
print(q.popleft()) # a
print(q) # deque(['b', 'c', 'd'], maxlen=10)
# 扩展队列
q.extend(['i', 'j'])
print(q) # deque(['b', 'c', 'd', 'i', 'j'], maxlen=10)
# 查找下标
print(q.index('c')) # 1
# 移除第一个'd'
q.remove('d')
print(q) # deque(['b', 'c', 'i', 'j'], maxlen=10)
# 逆序
q.reverse()
print(q) # deque(['j', 'i', 'c', 'b'], maxlen=10)
# 最大长度
print(q.maxlen) # 10
2.1.1 单调对列实现
蓝桥杯 MAX最值差
import os
import sys
# 请在此输入您的代码
from collections import deque
def findMaxdiff(n,k,a):
q1,q2=deque(),deque() # 建两个单调队列
res=-sys.maxsize
for i in range (n): # 遍历每一个元素
while q1 and a[q1[-1]]>=a[i]: #q1有元素且最后一个元素都大于a[i]
q1.pop()
q1.append(i)
while q1 and i-q1[0]>=k:
q1.popleft()
Fi=a[q1[0]]
while q2 and a[q2[-1]]<=a[i]: #q1有元素且最后一个元素都大于a[i]
q2.pop()
q2.append(i)
while q2 and i-q2[0]>=k:
q2.popleft()
Gi=a[q2[0]]
#计算最大差值
res=max(res,Gi-Fi)
return res
n,k=map(int,input().split())
A=list(map(int,input().split()))
print(findMaxdiff(n,k,A))
2.1.2 BFS广搜
蓝桥杯真题 跳蚂蚱
import collections
import sys
meet=False #判断是否相遇
def extend(q,m1,m2):
global meet
s=q.popleft()
ss=list(s)
index=ss.index('0') #找0的索引
for j in [1,-1,2,-2]:
ss[(index+j+9)%9],ss[index]= ss[index],ss[(index+j+9)%9]
a=''.join(ss)
if a in m2: # 找到相同的了,即相遇了
print(m1[s]+1+m2[a])
meet=True
return
if a not in m1:
q.append(a)
m1[a]=m1[s]+1 # 向字典中添加
ss[(index+j+9)%9],ss[index]= ss[index],ss[(index+j+9)%9]
# meet=False
q1=collections.deque()
q2=collections.deque()
q1.append("012345678")
q2.append("087654321")
# 字典去重,同时记录步数
mp1={'012345678':0} ; mp2={'087654321':0}
while q1 and q2 : # 两个都不为空
if len(q1)<=len(q2): extend(q1,mp1,mp2)
else: extend(q2,mp2,mp1)
if meet==True: break
3.sys
3.1 sys.maxsize
表示操作系统承载的最大int值
3.2 sys.exit()
中断程序运行
3.3 sys.stdin.readline()
快读,注意会读入回车符,感觉用处不大, 没提升多大效率
import sys
a = sys.stdin.readline()
b = input()
print(len(a), len(b))
a = sys.stdin.readline().strip('\n')
b = input()
print(len(a), len(b))
输出结果
123123 123123 adsfasdfd fefeggegeag fasdfa
123123 123123 adsfasdfd fefeggegeag fasdfa
43 42
123123 123123 adsfasdfd fefeggegeag fasdfa
123123 123123 adsfasdfd fefeggegeag fasdfa
42 42
3.4 sys.setrecursionlimit()
设置最大递归深度,默认的很小,有时候dfs会报错出现段错误。
sys.setrecursionlimit(10**6)
4.heapq
4.1 heapq.heapify(x)
将list x 转换成堆,原地,线性时间内。
import heapq
H = [21,1,45,78,3,5]
# Use heapify to rearrange the elements
heapq.heapify(H)
print(H)
[1, 3, 5, 78, 21, 45]
4.2 heapq.heappush(heap, item)
将 item 的值加入 heap 中,保持堆的不变性。
# Add element
heapq.heappush(H,8)
print(H)
[1, 3, 5, 78, 21, 45]
↓
[1, 3, 5, 78, 21, 45, 8]
4.3 heapq.heappop(heap)
弹出并返回 heap 的最小的元素,保持堆的不变性。如果堆为空,抛出 IndexError 。使用 heap[0] ,可以只访问最小的元素而不弹出它。
# Remove element from the heap
heapq.heappop(H)
print(H)
[1, 3, 5, 78, 21, 45, 8]
↓
[3, 21, 5, 78, 45]
4.4 堆优化的Dijstra
1.蓝桥杯国赛真题 出差
import os
import sys
import itertools
import heapq
# Bellman-Ford O(mn)
'''
n,m=map(int,input().split())
stay=[0]+list(map(int,input().split()))
stay[n]=0 # 终点不需要隔离
e=[]
for i in range(m):
a,b,c=map(int,input().split())
e.append([a,b,c])
e.append([b,a,c])
dp=[sys.maxsize for i in range(n+1)]
dp[1]=0 #到起点的距离为0
for i in range(1,n+1): # n个点
for j in e: # m条边
v1,v2,cost=j
#if v2==n: # n号城市不需要隔离时间
dp[v2]=min(dp[v2],dp[v1]+cost+stay[v2])
print(dp[n])
'''
# Dijstra 临接表写法 O(n*n)
'''
n,m=map(int,input().split())
stay=[0]+list(map(int,input().split()))
stay[n]=0 # 终点不需要隔离
edge=[[]for i in range(n+1)]
for i in range(m):
a,b,c=map(int,input().split())
edge[a].append([b,c+stay[b]])
edge[b].append([a,c+stay[a]])
hp=[]
vis=[0 for i in range(n+1)]
dp=[sys.maxsize for i in range(n+1)]
dp[1]=0 # 自身到自身距离为0
heapq.heappush(hp,(0,1))
while hp:
u=heapq.heappop(hp)[1]
if vis[u]:
continue
vis[u]=1
for i in range(len(edge[u])): # 遍历u的边
v,w=edge[u][i][0],edge[u][i][1]
if vis[v]:
continue
if dp[v]>dp[u]+w:
dp[v]=dp[u]+w
heapq.heappush(hp,(dp[v],v))
print(dp[n])
'''
# Dijstra临接矩阵写法 O(n*n)
'''
n,m=map(int,input().split())
stay=[0]+list(map(int,input().split()))
stay[n]=0 # 终点不需要隔离
edge=[[sys.maxsize for i in range(n+1)]for i in range(n+1)]
for i in range(m):
a,b,c=map(int,input().split())
edge[a][b]=c+stay[b]
edge[b][a]=c+stay[a]
vis=[0 for i in range(n+1)]
dp=[sys.maxsize for i in range(n+1)]
dp[1]=0 # 自身到自身距离为0
for i in range(n-1): #只需要处理n-1个点
t=-1
for j in range(1,n+1): # 找到没处理过得并且距离最小的
if vis[j]==0 and(t==-1 or dp[j]<dp[t] ):
t=j
for j in range(1,n+1):
dp[j]=min(dp[j],dp[t]+edge[t][j])
vis[t]=1
print(dp[n])
'''
# SPFA
n,m=map(int,input().split())
stay=[0]+list(map(int,input().split()))
stay[n]=0 # 终点不需要隔离
edge=[[]for i in range(n+1)] #临接表存边
for i in range(m):
a,b,c=map(int,input().split())
edge[a].append([b,c+stay[b]])
edge[b].append([a,c+stay[a]])
dp=[sys.maxsize for i in range(n+1)]
dp[1]=0 # 自身到自身距离为0
def spfa():
hp=[]
heapq.heappush(hp,1) #用堆实现相当于优先队列,加快一点效率罢了
in_hp=[0 for i in range(n+1)] # 标记数组换为了判断是否在队列中
in_hp[1]=1 # 1在队列
while hp:
u=heapq.heappop(hp)
in_hp[u]=0 # 标记为不在队列
if dp[u]==sys.maxsize: # 没有处理过的点,直接跳过,只处理邻居点
continue
for i in range(len(edge[u])): # 遍历u的边
v,w=edge[u][i][0],edge[u][i][1]
if dp[v]>dp[u]+w:
dp[v]=dp[u]+w
if in_hp[v]==0: # 他的邻居不再队列,就把他入队,方便下下次更新邻居的邻居结点
heapq.heappush(hp,v)
in_hp[v]=1
spfa()
print(dp[n])
4.5 通过堆实现的Kruskal算法
1.国赛真题 通电
import os
import sys
import math
import heapq # heapq 比 优先队列要快很多
input = sys.stdin.readline
n = int(input().strip())
root = [i for i in range(n+1)]
arr = [list(map(int, input().strip().split())) for i in range(n)] # n个点坐标 高度
# 计算距离
def dist(x1,y1,h1, x2,y2,h2):
return math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) + (h1-h2)*(h1-h2)
q = []
# 建立 n个点的的连通图
for i in range(n):
for j in range(i+1,n):
heapq.heappush(q, [dist(arr[i][0],arr[i][1],arr[i][2], arr[j][0],arr[j][1],arr[j][2]), i, j]) # 从 i到j牵线,并按距离排序
# 判断是否会形成环
def find(u):
if u != root[u]:
root[u] = find(root[u])
return root[u]
# Kruskal 算法实现步骤
def Kruskal():
ans = 0.00
cnt = 0
while q and cnt < n-1: # 图只需找n-1条边
c,a,b = heapq.heappop(q)
a_root = find(a)
b_root = find(b)
if a_root != b_root:
root[a_root] = b_root
ans += c
cnt += 1
print('%.2lf' % ans)
Kruskal()
"""
import os
import sys
# 请在此输入您的代码
import math
n=int(input())
def money(a,b):
ke=math.sqrt(pow(a[0]-b[0],2)+pow(a[1]-b[1],2))+pow(a[2]-b[2],2)
return ke
def prim():
global res
dist[0]=0
book[0]=1
for i in range(1,n):
dist[i]=min(dist[i],G[0][i])
for i in range(1,n):
cnt=float("inf")
t=-1
for j in range(1,n):
if book[j]==0 and dist[j]<cnt:
cnt=dist[j]
t=j
if t==-1 :
res=float("inf")
return
book[t]=1
res+=dist[t]
for j in range(1,n):
dist[j]=min(dist[j],G[t][j])
ls=[]
book=[0]*n
dist=[float("inf")]*n
res=0
for i in range(n):
ls.append(list(map(int,input().split())))
G=[[float("inf")]*n for _ in range(n)]
for i in range(n):
G[i][i]=float("inf")
for i in range(n):
for j in range(i+1,n):
G[i][j]=money(ls[i],ls[j])
G[j][i]=money(ls[i],ls[j])
prim()
print("{:.2f}".format(res))
"""
5.itertools
主要使用combinations和combinations。
5.1 combinations
itertools.combinations(iterable, r):生成可迭代对象的所有长度为r的组合。
5.2 permutations
itertools.permutations(iterable, r=None):生成可迭代对象的所有长度为r的排列,默认r为可迭代对象的长度。
5.3 例题
1.算式问题
import os
import sys
import itertools
# 请在此输入您的代码
L=[str(i) for i in range(1,10)]
ans=0
for i in itertools.permutations(L):
s=''.join(i)
if int(s[:3])+int(s[3:6])==int(s[6:]):
ans+=1
print(ans)
6.bisect
内置的二分查找函数,用于有序序列的插入和查找
6.1 bisect_left()
bisect.bisect_left(a, x, lo=0, hi=len(a))
若 x ∈ a,返回最左侧 x 的索引;否则返回与 x 右邻居索引,使得 x 若插入后能位于其 左侧。
6.2 bisect_right() 、bisect()
bisect.bisect(a, x, lo = 0, hi =len(a))
bisect.bisect_right(a, x, [lo=0, hi=len(a)])
若 x ∈ a,返回最左侧 x 的索引;否则返回与 x 右邻居索引,使得 x 若插入后能位于其 左侧。
6.3 insort_left()
bisect.insort_left(a, x, lo=0, hi=len(a))
bisect.bisect_left() 在序列 a 中 查找 元素 x 的插入点 (左侧)
bisect.insort_left() 就是在找到插入点的基础上,将元素 x 插入序列 a,从而改变序列 a 同时保持元素顺序。
6.4 insort_right()、insort()
bisect.insort(a, x, lo=0, hi=len(a))
bisect.insort_right(a, x, lo=0, hi=len(a))
6.5 示例
import bisect
nums = [0,1,2,3,4,4,6]
idx = bisect.bisect_left(nums,-1) # 0
idx = bisect.bisect_left(nums,8) # 7
idx = bisect.bisect_left(nums,3) # 3
idx = bisect.bisect_left(nums,3.5) # 4
idx = bisect.bisect_left(nums,4) # 4
idx = bisect.bisect_left(nums,3,1,4) # 3
a = [1,4,6,8,12,15,20]
position = bisect.bisect(a,13)
print(position) # 5
# 用可变序列内置的 insert 方法插入
a.insert(position, 13)
print(a) # 5 [1, 4, 6, 8, 12, 13, 15, 20]
查找的数不在列表中
import bisect
list1 = [1,3,5,7,9,11,11,11,11,11,13]
a = bisect.bisect(list1,6)
b = bisect.bisect_left(list1,6)
c = bisect.bisect_right(list1,6)
print(a,b,c)
# 输出为 3,3,3
查找的数在列表中只有一个
import bisect
list1 = [1,3,5,7,9,11,11,11,11,11,13]
a = bisect.bisect(list1,9)
b = bisect.bisect_left(list1,9)
c = bisect.bisect_right(list1,9)
print(a,b,c)
# 输出 5,4,5
查找的数在列表中有多个
import bisect
list1 = [1,3,5,7,9,11,11,11,11,11,13]
a = bisect.bisect(list1,11)
b = bisect.bisect_left(list1,11)
c = bisect.bisect_right(list1,11)
print(a,b,c)
# 输出是 10,5,10
6.6 例题1 最长上升子序列
1.蓝桥骑士
import os
import sys
'''
# 最长上升子序列
n = int(input())
a = list(map(int,input().split()))
f = [1]*n
for i in range(1,n):
for j in range(i):
if a[i] > a[j]:
f[i] = max(f[i],f[j]+1)
print(max(f))
'''
# 超时
'''
import bisect
n = int(input())
a = list(map(int,input().split()))
b = [a[0]]
for i in range(1,n):
t = bisect.bisect_left(b,a[i])
# 若b中不存在a[i],t是适合插入的位置
# 若b中存在a[i],t是a[i]第一个出现的位置
if t == len(b): # 插入的位置是否是末尾
b.append(a[i])
else:
b[t] = a[i]
print(len(b))
'''
import bisect
#蓝桥骑士 dp lis(Longest Increasing Subsequence)
n = int(input())
alist = list(map(int,input().split()))
dp = []
for i in alist:
if not dp or i > dp[-1]:
dp.append(i)
else:
index = bisect.bisect_left(dp,i)
dp[index]=i
print(len(dp))
2.蓝桥勇士
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
n=int(input())
save=[0]+list(map(int,input().split()))
dp=[1]*(n+1) # 注意初始化从1开始
for i in range(2,n+1):
for j in range(1,i):
if save[i]>save[j]:
dp[i]=max(dp[i],dp[j]+1)
print(max(dp)) #最长公共子序列,dp[n]不一定是最大的
# 1 4 5 2 1
# 1 2 3 2 1
6.7 例题2 最长上升子序列变形
import bisect # 内置二分查找
zifu = input()
A = [chr(65 + i) for i in range(26)]
s = ""
name = []
i = 0
zifu = zifu + "A" # 以后一个大写字符进行提取分隔
while i < len(zifu) - 1: # 提取数据格式为 name=[Wo,Ai,Lan,Qiao,Bei]
s += zifu[i]
if zifu[i + 1] in A:
name.append(s)
s = ""
i += 1
d = [name[0]]
p=[1] #存储下标
for i in name[1:]: # 遍历每一个字符
if i > d[-1]: # 大于,可以直接在后面接着
d.append(i) # 后面添加
p.append(len(d)) # 记录索引
else: # 查找第一个
k = bisect.bisect(d, i) # 使用bisect查找d中第一个大于等于i的元素,让其称为递增序列,有多个就是最右边的那个
if k > 0 and d[k - 1] == i: # 如果右索引的前一个数等于这个i的话,就将它替换掉,相等的不算递增????
k -= 1
d[k] = i
p.append(k+1) # 记录替换的索引
p0=p[::-1] #逆序遍历输出
s=len(d) # 最长有多少个递增子序列
ans=""
for i in range(len(p0)): #逆序遍历
if s==0:
break
if p0[i]==s:
ans=name[len(p)-i-1]+ans #加上name
s=s-1
print(ans)
Python知识教程
1.Python简介
-
Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。
-
Python 是交互式语言: 这意味着,您可以在一个 Python 提示符 >>> 后直接执行代码。
-
Python 是面向对象语言: 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。
-
Python 是初学者的语言:Python 对初级程序员而言,是一种伟大的语言,它支持广泛的应用程序开发,从简单的文字处理到 WWW 浏览器再到游戏。
2.Python中标准数据类型
常见数据类型
- Number(数字)
- String(字符串)
- bool(布尔类型)
- List(列表)
- Tuple(元组)
- Set(集合)
- Dictionary(字典)
Python3 的六个标准数据类型中:
- 不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);
- 可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。
3.Python3迭代器与生成器
迭代器
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
迭代器的创建
把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
输出结果
1
2
3
4
5
生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。
然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果。
代码实例文章来源:https://www.toymoban.com/news/detail-470279.html
def countdown(n):
while n > 0:
yield n
n -= 1
# 创建生成器对象
generator = countdown(5)
# 通过迭代生成器获取值
print(next(generator)) # 输出: 5
print(next(generator)) # 输出: 4
print(next(generator)) # 输出: 3
# 使用 for 循环迭代生成器
for value in generator:
print(value) # 输出: 2 1
4.Python面向对象
面向对象简介文章来源地址https://www.toymoban.com/news/detail-470279.html
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 方法:类中定义的函数。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
到了这里,关于竞赛中常用的Python 标准库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!