LeetCode Categories and Solution Templates
A quick reference to the most common LeetCode categories and battle‑tested Python templates to speed up implementation.
This guide is now split into category posts:
Contents
Arrays & Strings
Sliding Window (fixed/variable)
Use for subarray/substring with constraints (distinct count, sum/k, length).
# Variable-size window (e.g., longest substring without repeating)
def solve(self, s: str) -> int:
cnt = [0] * 256
dup = 0
best = 0
l = 0
for r in range(len(s)):
cnt[ord(s[r])] += 1
if cnt[ord(s[r])] == 2:
dup += 1
while dup > 0:
cnt[ord(s[l])] -= 1
if cnt[ord(s[l])] == 1:
dup -= 1
l += 1
best = max(best, r - l + 1)
return best
Examples: 3 Longest Substring Without Repeating Characters; 713 Subarray Product Less Than K (positive product, shrink while ≥ k); 76 Minimum Window Substring; 424 Longest Repeating Character Replacement.
| ID |
Title |
Link |
| 3 |
Longest Substring Without Repeating Characters |
https://leetcode.com/problems/longest-substring-without-repeating-characters/ |
| 713 |
Subarray Product Less Than K |
https://leetcode.com/problems/subarray-product-less-than-k/ |
| 76 |
Minimum Window Substring |
https://leetcode.com/problems/minimum-window-substring/ |
| 424 |
Longest Repeating Character Replacement |
https://leetcode.com/problems/longest-repeating-character-replacement/ |
Two Pointers (sorted arrays/strings)
# Classic: two-sum on sorted array, or merging
def twoSum(self, a: list[int], target: int) -> bool:
l, r = 0, len(a) - 1
while l < r:
s = a[l] + a[r]
if s == target:
return True
if s < target:
l += 1
else:
r -= 1
return False
Examples: 15 3Sum; 11 Container With Most Water; 125 Valid Palindrome.
| ID |
Title |
Link |
| 15 |
3Sum |
https://leetcode.com/problems/3sum/ |
| 11 |
Container With Most Water |
https://leetcode.com/problems/container-with-most-water/ |
| 125 |
Valid Palindrome |
https://leetcode.com/problems/valid-palindrome/ |
Binary Search on Answer (monotonic predicate)
# find minimum x s.t. predicate(x) == True
def binsearch(self, lo: int, hi: int, good: callable) -> int:
# [lo, hi] - find minimum x where good(x) is True
while lo < hi:
mid = (lo + hi) // 2
if good(mid):
hi = mid
else:
lo = mid + 1
return lo
Examples: 33 Search in Rotated Sorted Array; 34 First/Last Position; 162 Find Peak Element; 875 Koko Eating Bananas.
| ID |
Title |
Link |
| 33 |
Search in Rotated Sorted Array |
https://leetcode.com/problems/search-in-rotated-sorted-array/ |
| 34 |
Find First and Last Position of Element in Sorted Array |
https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/ |
| 162 |
Find Peak Element |
https://leetcode.com/problems/find-peak-element/ |
| 875 |
Koko Eating Bananas |
https://leetcode.com/problems/koko-eating-bananas/ |
Prefix Sum / Difference Array
# range sum queries
def prefix(a: list[int]) -> list[int]:
ps = [0] * (len(a) + 1)
for i in range(len(a)):
ps[i + 1] = ps[i] + a[i]
return ps
Examples: 560 Subarray Sum Equals K; 238 Product of Array Except Self; 525 Contiguous Array; 370 Range Addition.
| ID |
Title |
Link |
| 560 |
Subarray Sum Equals K |
https://leetcode.com/problems/subarray-sum-equals-k/ |
| 238 |
Product of Array Except Self |
https://leetcode.com/problems/product-of-array-except-self/ |
| 525 |
Contiguous Array |
https://leetcode.com/problems/contiguous-array/ |
| 370 |
Range Addition |
https://leetcode.com/problems/range-addition/ |
Hash Map Frequencies
# count frequencies and check uniqueness, etc.
from collections import defaultdict
freq = defaultdict(int)
for x in nums:
freq[x] += 1
Examples: 1 Two Sum; 49 Group Anagrams; 981 Time Based Key-Value Store; 359 Logger Rate Limiter.
| ID |
Title |
Link |
| 1 |
Two Sum |
https://leetcode.com/problems/two-sum/ |
| 49 |
Group Anagrams |
https://leetcode.com/problems/group-anagrams/ |
| 981 |
Time Based Key-Value Store |
https://leetcode.com/problems/time-based-key-value-store/ |
| 359 |
Logger Rate Limiter |
https://leetcode.com/problems/logger-rate-limiter/ |
Monotonic Stack (next greater / histogram)
# Next Greater Element (circular if needed)
def nextGreater(a: list[int]) -> list[int]:
n = len(a)
ans = [-1] * n
st = []
for i in range(2 * n):
idx = i % n
while st and a[st[-1]] < a[idx]:
ans[st[-1]] = a[idx]
st.pop()
if i < n:
st.append(idx)
return ans
Examples: 739 Daily Temperatures; 84 Largest Rectangle in Histogram; 239 Sliding Window Maximum.
| ID |
Title |
Link |
| 739 |
Daily Temperatures |
https://leetcode.com/problems/daily-temperatures/ |
| 84 |
Largest Rectangle in Histogram |
https://leetcode.com/problems/largest-rectangle-in-histogram/ |
| 239 |
Sliding Window Maximum |
https://leetcode.com/problems/sliding-window-maximum/ |
Monotonic Queue (Sliding Window Max)
| ID |
Title |
Link |
| 239 |
Sliding Window Maximum |
https://leetcode.com/problems/sliding-window-maximum/ |
| 1438 |
Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit |
https://leetcode.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/ |
| 862 |
Shortest Subarray with Sum at Least K |
https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/ |
Graph
BFS / Shortest Path (unweighted)
Grid BFS template (4-direction)
from collections import deque
def bfsGrid(self, g: list[str], s: tuple[int, int], t: tuple[int, int]) -> int:
m, n = len(g), len(g[0])
q = deque([s])
dist = [[-1] * n for _ in range(m)]
dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]
dist[s[0]][s[1]] = 0
while q:
x, y = q.popleft()
if (x, y) == t:
return dist[x][y]
for dx, dy in dirs:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n and g[nx][ny] != '#' and dist[nx][ny] == -1:
dist[nx][ny] = dist[x][y] + 1
q.append((nx, ny))
return -1
| ID |
Title |
Link |
| 200 |
Number of Islands |
https://leetcode.com/problems/number-of-islands/ |
| 417 |
Pacific Atlantic Water Flow |
https://leetcode.com/problems/pacific-atlantic-water-flow/ |
| 542 |
01 Matrix |
https://leetcode.com/problems/01-matrix/ |
DFS / Backtracking
# Subsets
def dfs(self, i: int, nums: list[int], cur: list[int], out: list[list[int]]) -> None:
if i == len(nums):
out.append(cur[:])
return
# skip
self.dfs(i + 1, nums, cur, out)
# take
cur.append(nums[i])
self.dfs(i + 1, nums, cur, out)
cur.pop()
| ID |
Title |
Link |
| 78 |
Subsets |
https://leetcode.com/problems/subsets/ |
| 46 |
Permutations |
https://leetcode.com/problems/permutations/ |
| 39 |
Combination Sum |
https://leetcode.com/problems/combination-sum/ |
| 77 |
Combinations |
https://leetcode.com/problems/combinations/ |
Trees
Tree Traversals (iterative)
Inorder (iterative)
def inorder(self, root: TreeNode) -> list[int]:
ans = []
st = []
cur = root
while cur or st:
while cur:
st.append(cur)
cur = cur.left
cur = st.pop()
ans.append(cur.val)
cur = cur.right
return ans
Level-order (BFS)
from collections import deque
def levelOrder(self, root: TreeNode) -> list[list[int]]:
if not root:
return []
res = []
q = deque([root])
while q:
sz = len(q)
level = []
for _ in range(sz):
u = q.popleft()
level.append(u.val)
if u.left:
q.append(u.left)
if u.right:
q.append(u.right)
res.append(level)
return res
LCA (Binary Lifting)
K = 17 # adjust for n (e.g., 17 for n<=1e5)
class LCA:
def __init__(self, n: int):
self.K = K
self.depth = [0] * n
self.up = [[-1] * (K + 1) for _ in range(n)]
def dfsLift(self, u: int, p: int, g: list[list[int]]) -> None:
self.up[u][0] = p
for k in range(1, self.K + 1):
if self.up[u][k - 1] < 0:
self.up[u][k] = -1
else:
self.up[u][k] = self.up[self.up[u][k - 1]][k - 1]
for v in g[u]:
if v != p:
self.depth[v] = self.depth[u] + 1
self.dfsLift(v, u, g)
def lift(self, u: int, k: int) -> int:
for i in range(self.K + 1):
if k & (1 << i):
if u < 0:
return -1
u = self.up[u][i]
return u
def lca(self, a: int, b: int) -> int:
if self.depth[a] < self.depth[b]:
a, b = b, a
a = self.lift(a, self.depth[a] - self.depth[b])
if a == b:
return a
for i in range(self.K, -1, -1):
if self.up[a][i] != self.up[b][i]:
a = self.up[a][i]
b = self.up[b][i]
return self.up[a][0]
| ID |
Title |
Link |
| 236 |
Lowest Common Ancestor of a Binary Tree |
https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/ |
| 235 |
Lowest Common Ancestor of a BST |
https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ |
HLD (Heavy-Light Decomposition) skeleton
# Heavy-Light Decomposition for path queries on a tree
# Build: dfs1 (sizes, heavy child), dfs2 (head/in), then segtree over in[]
class HLD:
def __init__(self, n: int, g: list[list[int]]):
self.n = n
self.g = g
self.szH = [0] * n
self.parH = [-1] * n
self.depH = [0] * n
self.heavyH = [-1] * n
self.headH = [0] * n
self.inH = [0] * n
self.curT = 0
def dfs1(self, u: int, p: int) -> int:
self.parH[u] = p
self.depH[u] = 0 if p == -1 else self.depH[p] + 1
self.szH[u] = 1
self.heavyH[u] = -1
best = 0
heavy = -1
for v in self.g[u]:
if v != p:
s = self.dfs1(v, u)
self.szH[u] += s
if s > best:
best = s
heavy = v
self.heavyH[u] = heavy
return self.szH[u]
def dfs2(self, u: int, h: int) -> None:
self.headH[u] = h
self.inH[u] = self.curT
self.curT += 1
if self.heavyH[u] != -1:
self.dfs2(self.heavyH[u], h)
for v in self.g[u]:
if v != self.parH[u] and v != self.heavyH[u]:
self.dfs2(v, v)
class SegTree:
def __init__(self, n: int):
self.n = n
self.st = [0] * (4 * n)
def upd(self, p: int, v: int, i: int = 1, l: int = 0, r: int = None) -> None:
if r is None:
r = self.n - 1
if l == r:
self.st[i] = v
return
m = (l + r) // 2
if p <= m:
self.upd(p, v, 2 * i, l, m)
else:
self.upd(p, v, 2 * i + 1, m + 1, r)
self.st[i] = self.st[2 * i] + self.st[2 * i + 1]
def qry(self, ql: int, qr: int, i: int = 1, l: int = 0, r: int = None) -> int:
if r is None:
r = self.n - 1
if qr < l or r < ql:
return 0
if ql <= l and r <= qr:
return self.st[i]
m = (l + r) // 2
return (
self.qry(ql, qr, 2 * i, l, m) +
self.qry(ql, qr, 2 * i + 1, m + 1, r)
)
def queryPath(a: int, b: int, seg: SegTree, hld: HLD) -> int:
res = 0
while hld.headH[a] != hld.headH[b]:
if hld.depH[hld.headH[a]] < hld.depH[hld.headH[b]]:
a, b = b, a
res += seg.qry(
hld.inH[hld.headH[a]],
hld.inH[a],
1,
0,
seg.n - 1
)
a = hld.parH[hld.headH[a]]
if hld.depH[a] > hld.depH[b]:
a, b = b, a
res += seg.qry(
hld.inH[a],
hld.inH[b],
1,
0,
seg.n - 1
)
return res
| ID |
Title |
Link |
| — |
(Rare in LC; use for path queries if needed) |
— |
Union-Find (Disjoint Set Union)
class DSU:
def __init__(self, n: int):
self.p = list(range(n))
self.r = [0] * n
def find(self, x: int) -> int:
if self.p[x] != x:
self.p[x] = self.find(self.p[x])
return self.p[x]
def unite(self, a: int, b: int) -> bool:
a = self.find(a)
b = self.find(b)
if a == b:
return False
if self.r[a] < self.r[b]:
a, b = b, a
self.p[b] = a
if self.r[a] == self.r[b]:
self.r[a] += 1
return True
| ID |
Title |
Link |
| 684 |
Redundant Connection |
https://leetcode.com/problems/redundant-connection/ |
| 721 |
Accounts Merge |
https://leetcode.com/problems/accounts-merge/ |
| 1319 |
Number of Operations to Make Network Connected |
https://leetcode.com/problems/number-of-operations-to-make-network-connected/ |
Heap / K-way Merge
import heapq
def mergeK(lists: list[list[int]]) -> list[int]:
# T = (val, list_idx, pos)
pq = []
for i, lst in enumerate(lists):
if lst:
heapq.heappush(pq, (lst[0], i, 0))
out = []
while pq:
v, i, j = heapq.heappop(pq)
out.append(v)
if j + 1 < len(lists[i]):
heapq.heappush(pq, (lists[i][j + 1], i, j + 1))
return out
| ID |
Title |
Link |
| 23 |
Merge k Sorted Lists |
https://leetcode.com/problems/merge-k-sorted-lists/ |
| 295 |
Find Median from Data Stream |
https://leetcode.com/problems/find-median-from-data-stream/ |
Topological Sort (Kahn / DFS)
from collections import deque
def topoKahn(n: int, g: list[list[int]]) -> list[int]:
indeg = [0] * n
for u in range(n):
for v in g[u]:
indeg[v] += 1
q = deque()
for i in range(n):
if indeg[i] == 0:
q.append(i)
order = []
while q:
u = q.popleft()
order.append(u)
for v in g[u]:
indeg[v] -= 1
if indeg[v] == 0:
q.append(v)
if len(order) != n:
return []
return order
| ID |
Title |
Link |
| 207 |
Course Schedule |
https://leetcode.com/problems/course-schedule/ |
| 210 |
Course Schedule II |
https://leetcode.com/problems/course-schedule-ii/ |
| 269 |
Alien Dictionary |
https://leetcode.com/problems/alien-dictionary/ |
Dijkstra (Shortest Path with Weights ≥ 0)
import heapq
def dijkstra(n: int, g: list[list[tuple[int, int]]], s: int) -> list[int]:
INF = 1 << 60
dist = [INF] * n
dist[s] = 0
pq = [(0, s)]
while pq:
d, u = heapq.heappop(pq)
if d != dist[u]:
continue
for v, w in g[u]:
if dist[v] > d + w:
dist[v] = d + w
heapq.heappush(pq, (dist[v], v))
return dist
| ID |
Title |
Link |
| 743 |
Network Delay Time |
https://leetcode.com/problems/network-delay-time/ |
| 1631 |
Path With Minimum Effort |
https://leetcode.com/problems/path-with-minimum-effort/ |
0-1 BFS (Edge Weights 0 or 1)
| ID |
Title |
Link |
| 1293 |
Shortest Path in a Grid with Obstacles Elimination |
https://leetcode.com/problems/shortest-path-in-a-grid-with-obstacles-elimination/ |
| 847 |
Shortest Path Visiting All Nodes |
https://leetcode.com/problems/shortest-path-visiting-all-nodes/ |
Trie (Prefix Tree)
| ID |
Title |
Link |
| 208 |
Implement Trie (Prefix Tree) |
https://leetcode.com/problems/implement-trie-prefix-tree/ |
| 211 |
Design Add and Search Words Data Structure |
https://leetcode.com/problems/design-add-and-search-words-data-structure/ |
| 212 |
Word Search II |
https://leetcode.com/problems/word-search-ii/ |
KMP (Substring Search)
| ID |
Title |
Link |
| 28 |
Find the Index of the First Occurrence in a String |
https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/ |
| 214 |
Shortest Palindrome |
https://leetcode.com/problems/shortest-palindrome/ |
LIS (Patience Sorting, O(n log n))
| ID |
Title |
Link |
| 300 |
Longest Increasing Subsequence |
https://leetcode.com/problems/longest-increasing-subsequence/ |
| 354 |
Russian Doll Envelopes |
https://leetcode.com/problems/russian-doll-envelopes/ |
Segment Tree (Range Query/Point Update)
| ID |
Title |
Link |
| 307 |
Range Sum Query – Mutable |
https://leetcode.com/problems/range-sum-query-mutable/ |
| 732 |
My Calendar III |
https://leetcode.com/problems/my-calendar-iii/ |
Fenwick Tree (Binary Indexed Tree)
| ID |
Title |
Link |
| 315 |
Count of Smaller Numbers After Self |
https://leetcode.com/problems/count-of-smaller-numbers-after-self/ |
| 307 |
Range Sum Query – Mutable |
https://leetcode.com/problems/range-sum-query-mutable/ |
Bitmask DP (TSP / subsets)
| ID |
Title |
Link |
| 847 |
Shortest Path Visiting All Nodes |
https://leetcode.com/problems/shortest-path-visiting-all-nodes/ |
| 698 |
Partition to K Equal Sum Subsets |
https://leetcode.com/problems/partition-to-k-equal-sum-subsets/ |
Math & Geometry
Math / Combinatorics (nCk mod P)
| ID |
Title |
Link |
| 62 |
Unique Paths |
https://leetcode.com/problems/unique-paths/ |
| 172 |
Factorial Trailing Zeroes |
https://leetcode.com/problems/factorial-trailing-zeroes/ |
Geometry Primitives (2D)
| ID |
Title |
Link |
| 149 |
Max Points on a Line |
https://leetcode.com/problems/max-points-on-a-line/ |
| 223 |
Rectangle Area |
https://leetcode.com/problems/rectangle-area/ |
Manacher (Longest Palindromic Substring, O(n))
| ID |
Title |
Link |
| 5 |
Longest Palindromic Substring |
https://leetcode.com/problems/longest-palindromic-substring/ |
Z-Algorithm (Pattern occurrences)
| ID |
Title |
Link |
| 1392 |
Longest Happy Prefix |
https://leetcode.com/problems/longest-happy-prefix/ |
Coordinate Compression
| ID |
Title |
Link |
| 315 |
Count of Smaller Numbers After Self |
https://leetcode.com/problems/count-of-smaller-numbers-after-self/ |
| 327 |
Count of Range Sum |
https://leetcode.com/problems/count-of-range-sum/ |
Meet-in-the-Middle (subset sums)
| ID |
Title |
Link |
| 1755 |
Closest Subsequence Sum |
https://leetcode.com/problems/closest-subsequence-sum/ |
| 805 |
Split Array With Same Average |
https://leetcode.com/problems/split-array-with-same-average/ |
Bitwise Trie (Max XOR Pair)
| ID |
Title |
Link |
| 421 |
Maximum XOR of Two Numbers in an Array |
https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/ |
Advanced Techniques
Tarjan SCC (Strongly Connected Components)
# Tarjan's algorithm: O(N+M) to label each node with SCC id
class TarjanSCC:
def __init__(self, n: int):
self.n = n
self.timer = 0
self.compCnt = 0
self.g = [[] for _ in range(n)]
self.tin = [-1] * n
self.low = [0] * n
self.comp = [-1] * n
self.st = []
self.in_stack = [False] * n
def addEdge(self, u: int, v: int) -> None:
self.g[u].append(v)
def dfs(self, u: int) -> None:
self.tin[u] = self.low[u] = self.timer
self.timer += 1
self.st.append(u)
self.in_stack[u] = True
for v in self.g[u]:
if self.tin[v] == -1:
self.dfs(v)
self.low[u] = min(self.low[u], self.low[v])
elif self.in_stack[v]:
self.low[u] = min(self.low[u], self.tin[v])
if self.low[u] == self.tin[u]:
while True:
v = self.st.pop()
self.in_stack[v] = False
self.comp[v] = self.compCnt
if v == u:
break
self.compCnt += 1
def run(self) -> int:
for i in range(self.n):
if self.tin[i] == -1:
self.dfs(i)
return self.compCnt
| ID |
Title |
Link |
| 1192 |
Critical Connections in a Network |
https://leetcode.com/problems/critical-connections-in-a-network/ |
| 802 |
Find Eventual Safe States (SCC/topo variant) |
https://leetcode.com/problems/find-eventual-safe-states/ |
Sweep Line (Intervals)
| ID |
Title |
Link |
| 218 |
The Skyline Problem |
https://leetcode.com/problems/the-skyline-problem/ |
| 253 |
Meeting Rooms II |
https://leetcode.com/problems/meeting-rooms-ii/ |
Greedy
| ID |
Title |
Link |
| 435 |
Non-overlapping Intervals |
https://leetcode.com/problems/non-overlapping-intervals/ |
| 56 |
Merge Intervals |
https://leetcode.com/problems/merge-intervals/ |
| 621 |
Task Scheduler |
https://leetcode.com/problems/task-scheduler/ |
# Interval scheduling: select max non-overlapping
def schedule(self, iv: list[tuple[int, int]]) -> int:
iv.sort(key=lambda x: x[1])
cnt = 0
end = -10**9
for s, e in iv:
if s >= end:
cnt += 1
end = e
return cnt
Recent solution posts (2026)
For curated links by theme (sliding window, trees, XOR, scheduling, and more), see the LeetCode Questions List section Problems by Category → Spring 2026 highlights, and the LeetCode Templates page Recent posts by category.