青岛手机网站设计公司网络营销方式举例
文章目录
- 栈
- 队列
- 堆
- 递归装饰器
- 并查集
- 树状数组
- 线段树
- 最近公共祖先LCA
- ST表
- 字典树
- KMP
- manacher
- 跳表(代替C++ STL的set)
- dijkstra
- 总结
栈
用list
代替
队列
用deque
双端队列替代
堆
用heapq
递归装饰器
众所周知,python的递归深度只有1000,根本满足不了大部分1e5以上的数据,当然你可以使用sys.setrecursionlimit(1000000)
扩到1e6,但是这会增加空间消耗,在一些竞赛OJ如codeforces,甚至你还没开始写就爆空间了,甚至会出现莫名其妙的段错误,因此尽可能少用。取而代之的是手写栈,但是手写栈有个问题就是像在写汇编代码,使用装饰器模拟递归栈,就可以正常写递归不怕爆栈了
def bootstrap(func, stk=[]):def wrapper(*args, **kwargs):if stk: # 递归一层返回return func(*args, **kwargs)else:# 遍历生成器函数gen = func(*args, **kwargs)while True:if type(gen) is GeneratorType: # 新的生成器函数stk.append(gen) # 入栈gen = next(gen) # 递归else: # 没有新的生成器函数stk.pop() # 弹出递归入口if not stk: # 全部遍历完了breakgen = stk[-1].send(gen)return gen # 返回答案return wrapper
不带返回值的调用,函数return改成yield,调用dfs需要加上yield
def solve():@bootstrapdef dfs(n):print(n)if n==0:yieldyield dfs(n-1)yield
带返回值的调用,经过实践可以修改装饰器代码使其带返回值,但是很容易出错,因此如果需要返回值,建议直接丢一个list到参数里面返回,因为list传的是引用
def solve():@bootstrapdef dfs(n,rval):if n==0:rval.append(0)yieldans=[]yield dfs(n-1,ans)rval.append(ans[0]+1) yieldans=[]dfs(5,ans)print(ans[0]) # 5
并查集
class DSU:def __init__(self,n):self.par=[i for i in range(n+1)]self.siz=[1]*(n+1)def find(self,x):if self.par[x]!=x:self.par[x]=self.find(self.par[x])return self.par[x]def merge(self,x,y):x=self.find(x)y=self.find(y)if x==y:return Falseself.par[y]=xself.siz[x]+=self.siz[y]return Truedef same(self,x,y):return self.find(x)==self.find(y)
树状数组
class Fenwick:def __init__(self,n):self.n=nself.t=[0]*(n+1)def add(self,x,y):while x<=self.n:self.t[x]+=yx+=x&-xdef query(self,x):ans=0while x:ans+=self.t[x]x-=x&-xreturn ans
线段树
class SegmentTree:class Node:def __init__(self,val=0):self.sum=valself.tag=0def __add__(self,t):return SegmentTree.Node(self.sum+t.sum)def __init__(self, n, default=Node()):self.n=nself.t=[default]*(n<<2)def pushup(self,p):self.t[p]=self.t[p<<1]+self.t[p<<1|1]def pushtag(self,p,tag,l,r):self.t[p].tag+=tagself.t[p].sum+=(r-l+1)*tagdef pushdown(self,p,l,mid,r):if self.t[p].tag:self.pushtag(p<<1,self.t[p].tag,l,mid)self.pushtag(p<<1|1,self.t[p].tag,mid+1,r)self.t[p].tag=0def build(self,p,l,r):if l==r:self.t[p]=self.Node()returnmid=l+r>>1self.build(p<<1,l,mid)self.build(p<<1|1,mid+1,r)self.pushup(p)def modify(self,p,l,r,ql,qr,x):if(ql<=l and r<=qr):self.pushtag(p,x,l,r)returnmid=l+r>>1self.pushdown(p,l,mid,r)if ql<=mid:self.modify(p<<1,l,mid,ql,qr,x)if qr>mid:self.modify(p<<1|1,mid+1,r,ql,qr,x)self.pushup(p)def modify(self,p,l,r,x,y):if l==r:self.t[p].sum+=yreturnmid=l+r>>1self.pushdown(p,l,mid,r)if x<=mid:self.modify(p<<1,l,mid,x,y)else:self.modify(p<<1|1,mid+1,r,x,y)self.pushup(p)def query(self,p,l,r,ql,qr):if ql<=l and r<=qr:return self.t[p]mid=l+r>>1self.pushdown(p,l,mid,r)ans=self.Node()if ql<=mid:ans+=self.query(p<<1,l,mid,ql,qr)if qr>mid:ans+=self.query(p<<1|1,mid+1,r,ql,qr)return ans
最近公共祖先LCA
N=int(1e5+10)
adj=[[] for _ in range(N)]
par=[[0]*30 for _ in range(N)]
dep=[0]*Ndef dfs(u,fa):par[u][0]=fadep[u]=dep[fa]+1for i in range(1,dep[u].bit_length()):par[u][i]=par[par[u][i-1]][i-1]for v in adj[u]:if v==fa: continuedfs(v,u)def lca(x,y):if dep[x]<dep[y]:x,y=y,xwhile(dep[x]!=dep[y]):x=par[x][(dep[x]-dep[y]).bit_length()-1]if x==y: return xfor i in range(dep[x].bit_length()-1,-1,-1):if par[x][i]!=par[y][i]:x=par[x][i]y=par[y][i]return par[x][0]
ST表
class SparseTable:def __init__(self,a,n):self.n=nself.m=n.bit_length()self.st=[[0]*self.m for _ in range(n+1)]for i in range(1,n+1):self.st[i][0]=a[i]for j in range(1,self.m):for i in range(1,n+1):if i+(1<<j)-1>n:breakself.st[i][j]=max(self.st[i][j-1],self.st[i+(1<<j-1)][j-1])def query(self,l,r):j=(r-l+1).bit_length()-1return max(self.st[l][j],self.st[r-(1<<j)+1][j])
字典树
class Trie:def __init__(self,n):self.tr=[[0]*26 for _ in range(n*26)]self.idx=0self.cnt=[0]*(n*26)def insert(self,s):p=0for c in s:c=ord(c)-ord('a')if not self.tr[p][c]:idx+=1self.tr[p][c]=self.idxp=self.tr[p][c] self.cnt[p]+=1 def query(self,s):p=0for c in s:c=ord(c)-ord('a')if not self.tr[p][c]:return 0 p=self.tr[p][c] return self.cnt[p]
KMP
def kmp(s):n = len(s)nxt = [0] * nj = 0for i in range(1, n):while j > 0 and s[i] != s[j]:j = nxt[j - 1]if s[i] == s[j]:j += 1nxt[i] = jreturn nxt
manacher
def manacher(s):s = '#' + '#'.join(s) + '#'n = len(s)p = [0] * nr, c = 0, 0for i in range(n):if i < r:p[i] = min(r - i, p[2 * c - i])while i - p[i] >= 0 and i + p[i] < n and s[i - p[i]] == s[i + p[i]]:p[i] += 1if i + p[i] > r:r = i + p[i]c = ireturn p
跳表(代替C++ STL的set)
感觉是目前最好的平替了,其他平衡树要么太难写没必要,像无旋平衡树这种常数又太大,跳表应该是最好的选择了
MAX_LEVEL = 32
P_FACTOR = 0.25def random_level() -> int:lv = 1while lv < MAX_LEVEL and random.random() < P_FACTOR:lv += 1return lvclass SkiplistNode:__slots__ = 'val', 'forward'def __init__(self, val: int, max_level=MAX_LEVEL):self.val = valself.forward = [None] * max_levelclass Skiplist:def __init__(self):self.head = SkiplistNode(-1)self.level = 0def search(self, target: int) -> bool:curr = self.headfor i in range(self.level - 1, -1, -1):# 找到第 i 层小于且最接近 target 的元素while curr.forward[i] and curr.forward[i].val < target:curr = curr.forward[i]curr = curr.forward[0]# 检测当前元素的值是否等于 targetreturn curr is not None and curr.val == targetdef add(self, num: int) -> None:update = [self.head] * MAX_LEVELcurr = self.headfor i in range(self.level - 1, -1, -1):# 找到第 i 层小于且最接近 num 的元素while curr.forward[i] and curr.forward[i].val < num:curr = curr.forward[i]update[i] = currlv = random_level()self.level = max(self.level, lv)new_node = SkiplistNode(num, lv)for i in range(lv):# 对第 i 层的状态进行更新,将当前元素的 forward 指向新的节点new_node.forward[i] = update[i].forward[i]update[i].forward[i] = new_nodedef erase(self, num: int) -> bool:update = [None] * MAX_LEVELcurr = self.headfor i in range(self.level - 1, -1, -1):# 找到第 i 层小于且最接近 num 的元素while curr.forward[i] and curr.forward[i].val < num:curr = curr.forward[i]update[i] = currcurr = curr.forward[0]if curr is None or curr.val != num: # 值不存在return Falsefor i in range(self.level):if update[i].forward[i] != curr:break# 对第 i 层的状态进行更新,将 forward 指向被删除节点的下一跳update[i].forward[i] = curr.forward[i]# 更新当前的 levelwhile self.level > 1 and self.head.forward[self.level - 1] is None:self.level -= 1return True
dijkstra
adj=[[] for _ in range(N)]
dis=[inf]*N
def dijkstra():dis[1]=0heap=[(0,1)] while heap:d,x=heappop(heap)if dis[x]<d:continuefor y,c in adj[x]:if d+c<dis[y]:dis[y]=d+cheappush(heap,(dis[y],y))
总结
省赛能用到的应该就这么多了,剩下的要么是思维,要么是模拟,要么是各种dp,后续进国赛再深度挖掘一下其他的模板