Last active
March 31, 2021 01:34
-
-
Save petulla/dcee2636e63cd9b6f0e4edf53b129bb1 to your computer and use it in GitHub Desktop.
Snippets for memorization/contests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Delete element from heap in O(logn) | |
def delete(num, heap): | |
index = heap.index(num) | |
heap[index] = heap[-1] | |
del heap[-1] | |
if index < len(heap): | |
heapq._siftup(heap, index) | |
heapq._siftdown(heap, 0, index) | |
## GCD | |
def gcd(x, y): | |
if x == 0: return y | |
return gcd(y % x, x) | |
## Fenwick | |
# via alex wice | |
class Fenwick: | |
def __init__(self, n): | |
sz = 1 | |
while sz <= n: | |
sz *= 2 | |
self.size = sz | |
self.data = [0] * sz | |
def sum(self, i): | |
s = 0 | |
while i > 0: | |
s += self.data[i] | |
i -= i & -i | |
return s | |
def add(self, i, x): | |
while i < self.size: | |
self.data[i] += x | |
i += i & -i | |
## Merkle tree | |
def traverse(node): | |
if not node: return '' | |
s = hash((traverse(node.left), str(node.val), traverse(node.right)) | |
return s | |
## LIC | |
def lic(sequence): | |
dp = [] | |
for i in range(len(sequence)): | |
i = bisect.bisect_left(dp, nums[i]) | |
if i == len(dp): | |
dp.append(nums[i]) | |
else: | |
dp[i] = nums[i] | |
return len(dp) | |
## Dijkstra | |
## Segment tree | |
## Morris traversal (inorder) | |
def inorderTraversal(root): | |
curr = root | |
res = [] | |
while curr: | |
if curr.left: | |
pre = curr.left | |
while pre.right and pre.right!=curr: | |
pre = pre.right | |
if pre.right == curr: | |
pre.right = None | |
res.append(curr.val) | |
curr = curr.right | |
else: | |
pre.right = curr | |
curr = curr.left | |
else: | |
res.append(curr.val) | |
curr = curr.right | |
return res | |
# DSU | |
class DSU: | |
def __init__(self, n: int): | |
self.target = n - 1 | |
self.dsu = {i:i for i in range(n)} | |
self.counts = [1] * n | |
def union(self, p, q): | |
root1 = self.find(p) | |
root2 = self.find(q) | |
if root1 == root2: return False | |
if self.counts[root1] < self.counts[root2]: | |
root1, root2 = root2, root1 | |
self.dsu[root2] = root1 | |
self.counts[root1] += self.counts[root2] | |
return True | |
def find(self, p): | |
while p != self.dsu[p]: | |
self.dsu[p] = self.dsu[self.dsu[p]] | |
p = self.dsu[p] | |
return p | |
@property | |
def connected(self): | |
return self.find(0) == self.find(self.target) | |
def size(self, p): | |
return self.counts[self.find(p)] | |
## Kruskal's | |
def MST(heights): | |
m, n = len(heights), len(heights[0]) | |
edges = self.gather_edges(heights) | |
heapq.heapify(edges) | |
DSU = DSU(m * n) | |
v = 0 | |
while not DSU.connected: | |
v, root, child = heapq.heappop(edges) | |
DSU.union(root, child) | |
return v | |
def gather_edges(self, D): | |
edges = [] | |
m,n = len(D), len(D[0]) | |
for i,j in itertools.product(range(m), range(n)): | |
from_id = n * i + j | |
if i: | |
value = abs(D[i][j] - D[i - 1][j]) | |
to_id = from_id - n | |
edges.append([value, from_id, to_id]) | |
if j: | |
value = abs(D[i][j] - D[i][j - 1]) | |
to_id = from_id - 1 | |
edges.append([value, from_id, to_id]) | |
return edges | |
## Prim's | |
def MST(A): | |
graph = defaultdict(list) | |
q = [(0, 0)] | |
visited = set() | |
for i, (x1,y1) in enumerate(A): | |
for j, (x2, y2) in enumerate(A[i + 1:], i + 1): | |
d = abs(x2 - x1) + abs(y2 - y1) | |
graph[i].append((d, j)) | |
graph[j].append((d, i)) | |
cost = 0 | |
while len(visited) < len(A): | |
d, i = heapq.heappop(q) | |
if i not in visited: | |
visited.add(i) | |
cost += d | |
for t in graph[i]: | |
heapq.heappush(q, t) | |
return cost | |
## Rabin-Karp | |
def findString(haystack: str, needle: str) -> int: | |
n, h = len(needle), len(haystack) | |
if n > h: return -1 | |
# multiplier, based on base digits/letters | |
a = 26 #10 | |
mod = 2**15 #how to choose? by extent of possible values | |
needle = [ord(n) - ord('a') for n in needle] | |
# this can also be a lambda function if you want to do one pass | |
haystack = [ord(h) - ord('a') for h in haystack] | |
t = ref_h = 0 | |
# build the reference hash | |
for i in range(n): | |
t = (t * a + haystack[i]) % mod | |
ref_h = (ref_h * a + needle[i]) % mod | |
if t == ref_h: return 0 | |
# const value to be used often : a**L % modulus | |
aL = pow(a, n, mod) | |
for start in range(1, h - n + 1): | |
# compute rolling hash in O(1) time | |
t = (t * a - haystack[start - 1] * aL + haystack[start + n - 1]) % mod | |
if t == ref_h: return start | |
return -1 | |
## Stars / bars | |
n + r - 1 choose r | |
## Inverse mod | |
pow(x, mod - 2, mod) | |
## Pow | |
def pow(x,n,m): | |
if n == 0: return 1 | |
if n == 1: return x | |
if n < 0: return pow(1/x,-n,m - 2) | |
return (pow(x * x,n // 2, m) % m)* (1 if n % 2 == 0 else x % m) | |
## LCP with Suffix arrray + Manber Myers | |
class Solution: | |
def build_lcp(self, s, sa): | |
n = len(sa) | |
rank = [0] * n | |
for i in range(n): | |
rank[sa[i]] = i | |
k = 0 | |
lcp = [0] * n | |
for i in range(n): | |
if rank[i] == n - 1: | |
k = 0 | |
continue | |
j = sa[rank[i] + 1] | |
while i + k < n and j + k < n and s[i + k] == s[j + k]: | |
k += 1 | |
lcp[rank[i]] = k | |
k = max(k - 1, 0) | |
return lcp | |
def suffix_array_manber_myers(self, s): | |
result = [] | |
def sort_bucket(s, bucket, order=1): | |
d = defaultdict(list) | |
for i in bucket: | |
key = s[i:i+order] | |
d[key].append(i) | |
for k, v in sorted(d.items()): | |
if len(v) > 1: | |
sort_bucket(s, v, order*2) | |
else: | |
result.append(v[0]) | |
return result | |
return sort_bucket(s, (i for i in range(len(s)))) | |
def countDistinct(self, s: str) -> int: | |
sa = self.suffix_array_manber_myers(s) | |
lcp = self.build_lcp(s, sa) | |
n = len(s) | |
return ((n * (n + 1)) // 2) - sum(lcp) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment