小 trick
overlap条件:start1 < end2 and end1 > start2
在DFS中我们说关键点是递归以及回溯,在BFS中,关键点则是状态的选取和标记
树算法
Binary Indexed Tree BIT 树状数组
class BIT:def __init__(self, n):self.n = n + 1self.sums = [0] * self.ndef update(self, i, delta):while i < self.n:self.sums[i] += deltai += i & (-i) # = i & (~i + 1) 用于追踪最低位的1def prefixSum(self, i):res = 0while i > 0:res += self.sums[i]i -= i & (-i)return resdef rangeSum(self, s, e):return self.prefixSum(e) - self.prefixSum(s - 1)
Binary Search Tree
class Node(object):def __init__(self, data):self.left = Noneself.right = Noneself.data = datadef insert(self, data):if self.data:if data < self.data:if self.left is None:self.left = Node(data)else:self.left.insert(data)elif data > self.data:if self.right is None:self.right = Node(data)else:self.right.insert(data)else:self.data = datadef search(self, data, parent=None):if data < self.data:if self.left is None:return None, Nonereturn self.left.search(data, self)elif data > self.data:if self.right is None:return None, Nonereturn self.right.search(data, self)else:return self, parent
Trie
import collectionsclass TrieNode():def __init__(self):self.children = collections.defaultdict(TrieNode)self.isEnd = Falseclass Trie():def __init__(self):self.root = TrieNode()def insert(self, word):node = self.rootfor w in word:node = node.children[w]node.isEnd = Truedef search(self, word):node = self.rootfor w in word:# dict.get() 找不到的话返回Nonenode = node.children.get(w)if not node:return Falsereturn node.isEnd
线段树
class SegmentTree(object):def __init__(self, nums, s=None, e=None): # buildself.lo, self.hi = s, eself.left, self.right = None, Noneself.mid = (self.lo+self.hi)/2self.val = 0if self.hi < self.lo:returnelif self.hi == self.lo:self.val = nums[self.lo]else: # self.lo < self.hiself.left = SegmentTree(nums, self.lo, self.mid)self.right = SegmentTree(nums, self.mid+1, self.hi)self.val = self.left.val + self.right.valdef update(self, i, val): # modifyif i == self.lo == self.hi:self.val = valelse:if i <= self.mid:self.left.update(i, val)else:self.right.update(i, val)self.val = self.left.val + self.right.valdef sumRange(self, i, j): # queryif i == self.lo and j == self.hi: # equalreturn self.valelif self.lo > j or self.hi < i: # not intersectreturn 0else: # intersectif i > self.mid: # all at the right sub treereturn self.right.sumRange(i, j)elif j <= self.mid: # all at the left sub treereturn self.left.sumRange(i, j)else: # some at the right & some at the leftreturn self.left.sumRange(i, self.mid) + self.right.sumRange(self.mid+1, j)def get(self, i):if self.lo == self.hi == i:return self.valelif self.lo > i or self.hi < i:return 0else:if i > self.mid: # rightreturn self.right.get(i)else: # leftreturn self.left.get(i)
排序算法
快速选择
quick select
def partition(nums, lo, hi):i, x = lo, nums[hi]for j in range(lo, hi):if nums[j] <= x:nums[i], nums[j] = nums[j], nums[i]i += 1nums[i], nums[hi] = nums[hi], nums[i]return idef quick_select(nums, lo, hi, k):while lo < hi:mid = partition(nums, lo, hi)if mid == k:return nums[k]elif mid < k:lo = mid+1else:hi = mid-1nums = [54, 26, 93, 17, 77, 31, 44, 55, 20]
for i in range(len(nums)):print(quick_select(nums, 0, len(nums)-1, i))
selection sort
def selection_sort(nums):for i in range(len(nums), 0, -1):tmp = 0for j in range(i):if not compare(nums[j], nums[tmp]):tmp = jnums[tmp], nums[i-1] = nums[i-1], nums[tmp]return nums
quick sort, in-place
def quick_sort(nums, l, r):if l >= r:returnpos = partition(nums, l, r)quick_sort(nums, l, pos-1)quick_sort(nums, pos+1, r)def partition(nums, lo, hi):i, x = lo, nums[hi]for j in range(lo, hi):if nums[j] <= x:nums[i], nums[j] = nums[j], nums[i]i += 1nums[i], nums[hi] = nums[hi], nums[i]return iarr = [4, 2, 1, 23, 2, 4, 2, 3]
quick_sort(arr, 0, len(arr)-1)
print(arr)
bubble sort
def bubble_sort(nums):for i in reversed(range(len(nums))):for j in range(i-1):if not compare(nums[j], nums[j+1]):nums[j], nums[j+1] = nums[j+1], nums[j]return nums
insertion sort
def insertion_sort(nums):for i in range(len(nums)):pos, cur = i, nums[i]while pos > 0 and not compare(nums[pos-1], cur):nums[pos] = nums[pos-1] # move one-step forwardpos -= 1nums[pos] = curreturn nums
merge sort
def merge_sort(nums):nums = mergeSort(nums, 0, len(nums)-1)return str(int("".join(map(str, nums))))def mergeSort(nums, l, r):if l > r:returnif l == r:return [nums[l]]mid = (r+l)//2left = mergeSort(nums, l, mid)right = mergeSort(nums, mid+1, r)return merge(left, right)def merge(l1, l2):res, i, j = [], 0, 0while i < len(l1) and j < len(l2):if not compare(l1[i], l2[j]):res.append(l2[j])j += 1else:res.append(l1[i])i += 1res.extend(l1[i:] or l2[j:]) # 喵 return res
图论算法
拓扑排序
两个defaultdict
一个graph
,一个in_degree
from collections import defaultdictdef findOrder(numCourses, prerequisites):graph = defaultdict(list)in_degree = defaultdict(int)for dest, src in prerequisites:graph[src].append(dest)in_degree[dest] += 1zero_degree = [k for k, v in in_degree.items() if v == 0]res = []while zero_degree:node = zero_degree.pop(0)res.append(node)for child in graph[node]:in_degree[child] -= 1if in_degree[child] == 0:zero_degree.append(child) # 同时也说这个元素该删除了return res
普利姆(Prime)算法
每个节点选cost最小的边
from collections import defaultdict
import heapqdef prim(vertexs, edges):adjacent_vertex = defaultdict(list)for v1, v2, length in edges:adjacent_vertex[v1].append((length, v1, v2))adjacent_vertex[v2].append((length, v2, v1))"""经过上述操作,将edges列表中各项归类成以某点为dictionary的key,其value则是其相邻的点以及边长。如下:defaultdict(<type 'list'>, {'A': [(7, 'A', 'B'), (5, 'A', 'D')],'C': [(8, 'C', 'B'), (5, 'C', 'E')],'B': [(7, 'B', 'A'), (8, 'B', 'C'), (9, 'B', 'D'), (7, 'B', 'E')],'E': [(7, 'E', 'B'), (5, 'E', 'C'), (15, 'E', 'D'), (8, 'E', 'F'), (9, 'E', 'G')],'D': [(5, 'D', 'A'), (9, 'D', 'B'), (15, 'D', 'E'), (6, 'D', 'F')],'G': [(9, 'G', 'E'), (11, 'G', 'F')],'F': [(6, 'F', 'D'), (8, 'F', 'E'), (11, 'F', 'G')]})"""res = [] # 存储最小生成树结果# vertexs是顶点列表,vertexs = list("ABCDEFG") == = > vertexs = ['A', 'B', 'C', 'D', 'E', 'F', 'G']visited = set(vertexs[0])# 得到adjacent_vertexs_edges中顶点是'A'(nodes[0]='A')的相邻点list,即adjacent_vertexs['A']=[(7,'A','B'),(5,'A','D')]adjacent_vertexs_edges = adjacent_vertex[vertexs[0]]# 将usable_edges加入到堆中,并能够实现用heappop从其中动态取出最小值。关于heapq模块功能,参考python官方文档heapq.heapify(adjacent_vertexs_edges)while adjacent_vertexs_edges:# 得到某个定点(做为adjacent_vertexs_edges的键)与相邻点距离(相邻点和边长/距离做为该键的值)最小值w, v1, v2 = heapq.heappop(adjacent_vertexs_edges)if v2 not in visited:# 在used中有第一选定的点'A',上面得到了距离A点最近的点'D',举例是5。将'd'追加到used中visited.add(v2)# 将v1,v2,w,第一次循环就是('A','D',5) append into resres.append((v1, v2, w))# 再找与d相邻的点,如果没有在heap中,则应用heappush压入堆内,以加入排序行列for next_vertex in adjacent_vertex[v2]:if next_vertex[2] not in visited:heapq.heappush(adjacent_vertexs_edges, next_vertex)return res# test
vertexs = list("ABCDEFG")
edges = [("A", "B", 7), ("A", "D", 5),("B", "C", 8), ("B", "D", 9),("B", "E", 7), ("C", "E", 5),("D", "E", 15), ("D", "F", 6),("E", "F", 8), ("E", "G", 9),("F", "G", 11)]print("edges:", edges)
print("prim:", prim(vertexs, edges))
Dijkstra[单源最短路径算法]
- Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径
- 以起始点为中心向外层层扩展,直到扩展到终点为止
- 要求图中不存在负权边
import sysdef dijkstra(graph):n = len(graph)dist = [sys.maxsize] * ndist[0] = 0 # 自己和自己距离为0visited = set()def minDistance():# 找到还没确定的里面距离最小的min_ans, min_index = min((dis, i)for i, dis in enumerate(dist) if i not in visited)return min_indexfor _ in range(n):min_index = minDistance()# 已经确定了visited.add(min_index)for v in range(n):if v not in visited and graph[min_index][v] > 0:# graph[min_index][v] > 0 表示存在这个路径new_dist = dist[min_index] + graph[min_index][v]if dist[v] > new_dist: # 表示值得被更新dist[v] = new_distprint(dist)# Driver program
graph = [[0, 4, 0, 0, 0, 0, 0, 8, 0],[4, 0, 8, 0, 0, 0, 0, 11, 0],[0, 8, 0, 7, 0, 4, 0, 0, 2],[0, 0, 7, 0, 9, 14, 0, 0, 0],[0, 0, 0, 9, 0, 10, 0, 0, 0],[0, 0, 4, 14, 10, 0, 2, 0, 0],[0, 0, 0, 0, 0, 2, 0, 1, 6],[8, 11, 0, 0, 0, 0, 1, 0, 7],[0, 0, 2, 0, 0, 0, 6, 7, 0]]dijkstra(graph)
Floyd[任意两点间的最短路径]
a.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
b.对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。
Inf = 65535 # 代表无穷大
arr = [[0, 10, Inf, Inf, Inf, 11, Inf, Inf, Inf], # 邻接矩阵[10, 0, 18, Inf, Inf, Inf, 16, Inf, 12],[Inf, 18, 0, 22, Inf, Inf, Inf, Inf, 8],[Inf, Inf, 22, 0, 20, Inf, Inf, 16, 21],[Inf, Inf, Inf, 20, 0, 26, Inf, 7, Inf],[11, Inf, Inf, Inf, 26, 0, 17, Inf, Inf],[Inf, 16, Inf, 24, Inf, 17, 0, 19, Inf],[Inf, Inf, Inf, 16, 7, Inf, 19, 0, Inf],[Inf, 12, 8, 21, Inf, Inf, Inf, Inf, 0]]n = len(arr) # 邻接矩阵大小
path = [[-1]*n for _ in range(n)]for k in range(n): # k在第一层for i in range(n):for j in range(n):if(arr[i][j] > arr[i][k]+arr[k][j]): # 两个顶点直接较小的间接路径替换较大的直接路径arr[i][j] = arr[i][k]+arr[k][j]path[i][j] = k # 记录新路径的前驱
for x in arr:print(x)
print()
for x in path:print(x)
字符串算法
KMP
class Solution(object):def strStr(self, haystack, needle):""":type haystack: str:type needle: str:rtype: int"""if not needle: return 0# build nextnext = [0]*len(needle)l, r = 0, 1while r < len(needle):if needle[l] == needle[r]:next[r] = l+1l, r = l+1, r+1elif l: l = next[l-1]else: r += 1# find idxl, r = 0, 0while r < len(haystack):if needle[l] == haystack[r]:if l == len(needle)-1:return r-ll, r = l+1, r+1elif l: l = next[l-1]else: r += 1return -1
Rabin-Karp Hash
class RabinKarpHash:def __init__(self, base, mod=int(1e9+7)):self.base = baseself.mod = moddef hash(self, arr):h = 0for val in arr:h = ((h * self.base) + val) % self.modreturn hdef roll(self, origin_hash, drop_val, new_val, max_base):h = origin_hash - (drop_val * max_base % self.mod)h = ((h*self.base)+new_val+self.mod)%self.modreturn hdef get_max_base(self, length):ret = 1for i in range(length-1):ret = (ret*self.base) % self.modreturn ret
Manacher’s Algorithm
https://www.geeksforgeeks.org/manachers-algorithm-linear-time-longest-palindromic-substring-part-4/
def findLongestPalindromicString(text):length = len(text)if length == 0:returnN = 2*length+1 # Position countL = [0] * NL[0] = 0L[1] = 1C = 1 # centerPositionR = 2 # centerRightPositioni = 0 # currentRightPositioniMirror = 0 # currentLeftPositionmaxLPSLength = 0maxLPSCenterPosition = 0diff = -1for i in range(2, N):# get currentLeftPosition iMirror for currentRightPosition iiMirror = 2*C-iL[i] = 0 # 初始化范围diff = R - i # 当前位置离上一个边界的距离# If currentRightPosition i is within centerRightPosition Rif diff > 0: # 利用对称性获取L[i]的最小值L[i] = min(L[iMirror], diff)# 计算当前palindrome长度while (True):# 边界条件con1 = (i + L[i]) < N and (i - L[i]) > 0if (not con1):break# 奇数位置需要比较char# 偶数位置直接加一con2 = (i + L[i]) % 2 == 1left_radius = int((i + L[i] + 1) / 2)right_radius = int((i - L[i] - 1) / 2)con31 = 0 <= left_radius and left_radius < lengthcon32 = 0 <= right_radius and right_radius < lengthcon3 = con31 and con32 and (text[left_radius] == text[right_radius])if(con2 or con3):L[i] += 1else:breakif L[i] > maxLPSLength: # Track maxLPSLengthmaxLPSLength = L[i]maxLPSCenterPosition = i# 触及上一个边界的话选择centerif i + L[i] > R:C = i# 更新边界为当前的边界R = i + L[i]# Uncomment it to print LPS Length array# printf("%d ", L[i]);start = int((maxLPSCenterPosition - maxLPSLength) / 2)end = int(start + maxLPSLength)print(text[start:end])# Driver program
text1 = "babcbabcbaccba"
findLongestPalindromicString(text1)
链表相关
优雅地遍历链表
while head:head = head.next
standard linked list reversing
class Solution:def reverseList(self, head):cur, prev = head, Nonewhile cur:cur.next, cur, prev = prev, cur.next, cur # standard reversingreturn prev
merge sort list
class Solution(object):def merge(self, h1, h2):dummy = tail = ListNode(None)while h1 and h2:if h1.val < h2.val:tail.next, tail, h1 = h1, h1, h1.nextelse:tail.next, tail, h2 = h2, h2, h2.nexttail.next = h1 or h2return dummy.nextdef sortList(self, head):if not head or not head.next:return headpre, slow, fast = None, head, headwhile fast and fast.next:pre, slow, fast = slow, slow.next, fast.next.nextpre.next = Nonereturn self.merge(self.sortList(head), self.sortList(slow))
二分
标准二分(bisect)
永远是lo = mid+1
, hi = mid
,返回lo
,lo=0, hi=n
# 等价于 bisect
# 保证 选的数>k 严格大于
def bisect_right(a, x, lo=0, hi=None):lo, hi = 0, nwhile lo < hi:mid = (lo+hi)//2if x < a[mid]:hi = mid # disgard equals partelse:lo = mid+1return lo# bisect_left is more useful at hand, since it returns the exact index of the element being looked up if it is present in the list
# 保证 选的数>=k 大于等于
def bisect_left(a, x, lo=0, hi=None):lo, hi = 0, nwhile lo < hi:mid = (lo+hi)//2if a[mid] < x:lo = mid+1 # disgard equals partelse:hi = midreturn lo>>> import bisect
>>> bisect.bisect_left([1,2,3], 2)
1
>>> bisect.bisect_right([1,2,3], 2)
2
范围都是[0-n]
import bisect
print(bisect.bisect_left([1, 2, 3], -1)) # 0
print(bisect.bisect_left([1, 2, 3], 0)) # 0
print(bisect.bisect_left([1, 2, 3], 1)) # 0
print(bisect.bisect_left([1, 2, 3], 2)) # 1
print(bisect.bisect_left([1, 2, 3], 3)) # 2
print(bisect.bisect_left([1, 2, 3], 4)) # 3print(bisect.bisect([1, 2, 3], -1)) # 0
print(bisect.bisect([1, 2, 3], 0)) # 0
print(bisect.bisect([1, 2, 3], 1)) # 1
print(bisect.bisect([1, 2, 3], 2)) # 2
print(bisect.bisect([1, 2, 3], 3)) # 3
print(bisect.bisect([1, 2, 3], 4)) # 3
二分最优问题
都是 (lo+hi)//2
, helper(mid) >= K
, hi = mid-1
, lo = mid+1
# 最大
# 找到最大的mid使得helper(mid)>=K
lo, hi = 1, sum(sweetness)
while lo <= hi:# 找到最大的mid使得count>=Kmid = (lo+hi)//2if helper(mid) >= K: # mid还可以再大一点lo = mid+1else:hi = mid-1return hi # 返回的是hi# 最小
# 找到最小的mid使得helper(mid)>=K
lo, hi = 1, sum(sweetness)
while lo <= hi:# 找到最大的mid使得count>=Kmid = (lo+hi)//2if helper(mid) >= K: # mid还可以再大一点hi = mid-1else:lo = mid+1return lo # 返回的是lo
搜索算法
并查集 Union-Find Set (General)
class UF:def __init__(self, n):self.parent = list(range(n+1))def find(self, i):if self.parent[i] != i: # 用i来判断self.parent[i] = self.find(self.parent[i]) # 路径压缩return self.parent[i]def union(self, x, y):self.parent[self.find(x)] = self.find(y)
回溯法通用模板
def combine(self, n, k):ans = []def helper(cur, start):if len(cur) == k:ans.append(cur[:])returnelse:for i in range(start+1, n+1):cur.append(i)helper(cur, i)cur.pop()helper([], 0)return ans
A星算法核心公式
F = G + H
F - 方块的总移动代价 G - 开始点到当前方块的移动代价 H - 当前方块到结束点的预估移动代价[heuristic]
import heapqdef heuristic(a, b):return (b[0] - a[0]) ** 2 + (b[1] - a[1]) ** 2def astar(array, start, destination):n, m = len(array), len(array[0])dirs = [(0, 1), (0, -1), (1, 0), (-1, 0),(1, 1), (1, -1), (-1, 1), (-1, -1)]visited = set()came_from = {}gscore = {start: 0}fscore = {start: heuristic(start, destination)}queue = []heapq.heappush(queue, (fscore[start], start))while queue:score, cur_pos = heapq.heappop(queue)if cur_pos == destination:data = []while cur_pos in came_from:data.append(cur_pos)cur_pos = came_from[cur_pos]return datavisited.add(cur_pos)for i, j in dirs:x, y = cur_pos[0] + i, cur_pos[1] + jneibor = (x, y)g = gscore[cur_pos]h = heuristic(cur_pos, neibor)f = g+hif (not(0 <= x < n and 0 <= y < m) # 不能越界or array[x][y] == 1 # 墙不能走or(neibor in visited and f >= gscore.get(neibor, 0))): # 还不如从0直接过来continueif g < gscore.get(neibor, 0) or neibor not in [i[1]for i in queue]:came_from[neibor] = cur_posgscore[neibor] = gfscore[neibor] = g + heuristic(neibor, destination)heapq.heappush(queue, (fscore[neibor], neibor))return Falsenmap = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]print(astar(nmap, (0, 0), (10, 13)))def heuristic(a, b):(x1, y1) = a(x2, y2) = breturn abs(x1 - x2) + abs(y1 - y2)def a_star_search(graph, start, goal):frontier = PriorityQueue()frontier.put(start, 0)came_from = {}cost_so_far = {}came_from[start] = Nonecost_so_far[start] = 0while not frontier.empty():current = frontier.get()if current == goal:breakfor next in graph.neighbors(current):new_cost = cost_so_far[current] + graph.cost(current, next)if next not in cost_so_far or new_cost < cost_so_far[next]:cost_so_far[next] = new_costpriority = new_cost + heuristic(goal, next)frontier.put(next, priority)came_from[next] = currentreturn came_from, cost_so_far
数学方法
素数筛法
# 1不是素数,最小的质数是2
# Prime table
maxInteger = 1000000
prime = [True]*maxInteger
prime[0] = False
prime[1] = False
for i in range(2, (int)(math.sqrt(maxInteger)+1)):if prime[i]:for j in range(i*i, maxInteger, i):prime[j] = False
求因数
# Given a list A, return all prime factors of elements in A
def getAllFactors(A):factors = []for x in A:facs = []# 筛法优化k, d = 0, primes[k]while d * :if x % d == 0:while x % d == 0:x //= dfacs.append(d)k += 1d = primes[k]# 特判,x>1说明有残余的质数,not facs说明x本身是质数if x > 1 or not facs:facs.append(x)factors.append(facs)
黄金比例求斐波那契
class Solution:def fib(self, N):golden_ratio = (1 + 5 ** 0.5) / 2return int((golden_ratio ** N + 1) / 5 ** 0.5)
$$ phi=frac{1+sqrt{5}}{2} approx 1.61803 $$
快速幂
def fastExpMod(a, b):res = 1while b:if (b & 1):# ei = 1, then mulres *= ab >>= 1# b, b^2, b^4, b^8, ... , b^(2^n)a *= areturn res
牛顿法
class Solution:def mySqrt(self, x):r = x + 1 # avoid dividing 0while r*r > x:r = int((r+x/r)/2) # newton's methodreturn r
GCD
def gcd(a, b):while b:a, b = b, a % breturn a
求多个数的GCD
def arr_gcd(self, A):gcd = A[0]for a in A:while a:gcd, a = a, gcd % areturn gcd
graycode
def grayCode(n):res = [0]i = 0while i < n: # 从2的0次方开始,next_base = 1 << ires_inv = [x + next_base for x in reversed(res)]res.extend(res_inv)i += 1return res# 长度为4的所有graycode
# 用于遍历所有情况
# 0000
# 0001
# 0011
# 0010
# 0110
# 0111
# 0101
# 0100
# 1100
# 1101
# 1111
# 1110
# 1010
# 1011
# 1001
# 1000
专用方法
单调栈
def foo(nums):st = []res = [0]*len(nums)for i, x in enumerate(nums):while st and nums[st[-1]] < x:idx = st.pop()res[idx] = i-idxst.append(i)return res
slide window
一个for 一个 while 不容易出错
class Window:def __init__(self):self.count = collections.Counter()self.reserve = 0def add(self, x):if self.count[x] == 0: # 从效果上来判断self.reserve += 1self.count[x] += 1def remove(self, x):self.count[x] -= 1if self.count[x] == 0: #self.reserve -= 1class Solution(object):def lengthOfLongestSubstringKDistinct(self, A, K):if not A or not len(A) or not K:return 0win = Window()ans = l = 0# 一个for 一个 while 不容易出错for r, x in enumerate(A):win.add(x)while win.reserve > K:win.remove(A[l])l += 1ans = max(r-l+1, ans)return ans
二维数组前缀和
n, m = len(grid), len(grid[0])
pre_sum = [[0]*(m+1) for _ in range(n+1)]for i in range(n):for j in range(m):pre_sum[i][j] = pre_sum[i][j-1] + pre_sum[i-1][j] - pre_sum[i-1][j-1] + grid[i][j]def get_sum(x0, y0, x1, y1):return pre_sum[x1][y1] - pre_sum[x0-1][y1] - pre_sum[x1][y0-1] + pre_sum[x0-1][y0-1]def helper(size):cur_max_sum = max(get_sum(x, y, x+size-1, y+size-1)for x in range(n-size+1) for y in range(m-size+1))return cur_max_sum
RMQ/ST[Sparse Table]算法
import mathclass ST:def __init__(self, arr):self.arr = arrself.n = n = len(arr)self.m = m = int(math.log(n, 2))self.maxsum = maxsum = [[0]*(m+1) for _ in range(n)]self.minsum = minsum = [[0]*(m+1) for _ in range(n)]for i, x in enumerate(arr):maxsum[i][0] = minsum[i][0] = xfor j in range(m):for i in range(n):k = i + (1 << j)if(k < n):maxsum[i][j+1] = max(maxsum[i][j], maxsum[k][j])minsum[i][j+1] = min(minsum[i][j], minsum[k][j])def get_max(self, a, b):k = int(math.log(b-a+1, 2))# 一头一尾return max(self.maxsum[a][k], self.maxsum[b-(1 << k)+1][k])def get_min(self, a, b):k = int(math.log(b-a+1, 2))return min(self.minsum[a][k], self.minsum[b-(1 << k)+1][k])arr = [3, 4, 5, 7, 8, 9, 0, 3, 4, 5]
st = ST(arr)
print(st.get_max(0, 9)) # 9
print(st.get_max(6, 9)) # 5
print(st.get_min(0, 9)) # 0
print(st.get_min(0, 4)) # 3
LZ77
def compress(message):win_size = 10 # 窗口长度pointer = 0 # 指针,初始指向第一个位置compressed_message = []while pointer < len(message):matched_length = 0 # 匹配到的长度# 窗口的corner casewindow = message[max(pointer - win_size, 0):pointer]# 能找到的最大长度while window.find(message[pointer:pointer + matched_length + 1]) != -1:matched_length += 1e = pointer + matched_length# window.find(message[start:end]) 相对窗口的offset# max(start - win_size, 0) 整个窗口的offset# first:在整个字符串中的offsetfirst_appear = window.find(message[pointer:e]) + max(pointer - win_size, 0)item = (pointer - first_appear, matched_length, message[e])compressed_message.append(item)pointer += matched_length + 1return compressed_messageprint(compress("abcdbbccaaabaeaaabaee"))
优雅地先序遍历
def preorder(self, root):if (not root):return ["null"]return [str(root.val)]+self.preorder(root.left)+self.preorder(root.right)def serialize(self, root):return ",".join(self.preorder(root))