#
Ready-to-go LeetCode templates
#
Basic Utilities
#
Count character frequency
def countFreq(s: str) -> dict[str, int]:
frequency = {} # key is character, value is frequency count
for char in s:
frequency[char] = frequency.get(char, 0) + 1
return frequency
#
Binary Search
Returns -1 if target
is not found
def binSearch(arr: list[int], target: int) -> int:
if len(arr) == 0:
return -1
l, r = 0, len(arr) - 1
while l <= r:
mid = (l + r) // 2
if arr[mid] == target:
return mid
elif arr[mid] > target:
r = mid - 1
else:
l = mid + 1
return -1
#
Whatever first search
#
Adjacency List
Suppose the graph is stored as
type Graph = dict[str, list[str]]
BFS
DFS
from collections import deque
def bfs(G: dict[str, list[str]], start: str):
queue = deque()
seen = set[str]()
queue.append(start)
while len(queue) > 0:
u = queue.popleft()
if u in seen:
continue
# process u here
seen.add(u)
for adj in G[u]:
queue.append(adj)
from collections import deque
def dfs(G: dict[str, list[str]], start: str):
stack = deque()
seen = set[str]()
stack.append(start)
while len(stack) > 0:
u = stack.pop()
if u in seen:
continue
# process u here
seen.add(u)
for adj in G[u]:
stack.append(adj)
def dfs(G: dict[str, list[str]], start: str):
seen = set[str]()
def dfsVisit(G: dict[str, list[str]], curr: str):
# Pre-process
seen.add(curr)
for adjacent in G[curr]:
if adjacent not in seen:
dfsVisit(G, adjacent)
# Post-process
for vertex in G:
# handle disconnected graphs
if vertex not in seen:
dfsVisit(G, vertex)
This assumes min-heap (elements with numerically smaller priority is popped first). Negate the priority value if max-heap is needed.
import heapq # min heap
from typing import Callable
type PriorityFn = Callable[[str, str], int | float]
def bestFirst(
G: dict[str, list[str]], start: str, priority: PriorityFn
):
queue = []
seen = set()
heapq.heappush(queue, (0, start))
while len(queue) > 0:
_, u = heapq.heappop(queue)
if u in seen:
continue
print(u)
seen.add(u)
for adj in G[u]:
heapq.heappush(queue, (priority(u, adj), adj))
#
Grid
For simplicity we assume the grid is not empty and the first element is a list, i.e. an empty grid is [[]]
. Validate the grid if necessary.
from collections import deque
def bfsGrid(grid: list[list[int]], start: tuple[int, int]):
R = len(grid)
C = len(grid[0])
# add more directions here if needed
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
seen = set()
queue = deque()
queue.append(start)
while len(queue) > 0:
r, c = queue.popleft() # use .pop() for dfs
if (r, c) in seen:
continue
seen.add((r, c))
# process grid[r][c] here
for dr, dc in directions:
nr = r + dr # new r
nc = c + dc # new c
if nr >= 0 and nr < R and nc >= 0 and nc < C:
queue.append((nr, nc))
def dfsGrid(grid: list[list[int]], start: tuple[int, int]):
R = len(grid)
C = len(grid[0])
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
seen = set()
def dfsVisit(grid: list[list[int]], curr: tuple[int, int]):
# pre-process curr
seen.add(curr)
r, c = curr
for dr, dc in directions:
nr = r + dr # new r
nc = c + dc # new c
if nr >= 0 and nr < R and nc >= 0 and nc < C:
dfsVisit(grid, (nr, nc))
# post-process curr
dfsVisit(grid, start) # optional, enforce starting position
# handle disconnected graphs
for r in range(R):
for c in range(C):
if (r, c) not in seen:
dfsVisit(grid, (r, c))
import heapq
from typing import Callable
def bestFirstGrid(
grid: list[list[int]],
start: tuple[int, int],
priority: Callable[..., int | float],
):
R = len(grid)
C = len(grid[0])
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
seen = set()
queue = []
queue.append((0, *start))
while len(queue) > 0:
_, r, c = heapq.heappop(queue)
if (r, c) in seen:
continue
seen.add((r, c))
# process grid[r][c]
for dr, dc in directions:
nr = r + dr
nc = c + dc
if nr >= 0 and nr < R and nc >= 0 and nc < C:
# priorityFn call signature could be different
heapq.heappush(queue, (priority(grid, nr, nc), nr, nc))