Created
April 11, 2023 22:11
-
-
Save nazariyv/f54fbacebeb11903cfa0743031d9edee to your computer and use it in GitHub Desktop.
code templates from the leetcode's: https://leetcode.com/explore/interview/card/leetcodes-interview-crash-course-data-structures-and-algorithms/
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
Two pointers: one input, opposite ends | |
```python3 | |
def fn(arr): | |
left = ans = 0 | |
right = len(arr) - 1 | |
while left < right: | |
# do some logic here with left and right | |
if CONDITION: | |
left += 1 | |
else: | |
right -= 1 | |
return ans | |
``` | |
```javascript | |
let fn = arr => { | |
let left = 0, ans = 0, right = arr.length - 1; | |
while (left < right) { | |
// do some logic here with left and right | |
if (CONDITION) { | |
left++; | |
} else { | |
right--; | |
} | |
} | |
return ans; | |
} | |
``` | |
Two pointers: two inputs, exhaust both | |
```python | |
def fn(arr1, arr2): | |
i = j = ans = 0 | |
while i < len(arr1) and j < len(arr2): | |
# do some logic here | |
if CONDITION: | |
i += 1 | |
else: | |
j += 1 | |
while i < len(arr1): | |
# do logic | |
i += 1 | |
while j < len(arr2): | |
# do logic | |
j += 1 | |
return ans | |
``` | |
```javascript | |
let fn = (arr1, arr2) => { | |
let i = 0, j = 0, ans = 0; | |
while (i < arr1.length && j < arr2.length) { | |
// do some logic here | |
if (CONDITION) { | |
i++; | |
} else { | |
j++; | |
} | |
} | |
while (i < arr1.length) { | |
// do logic | |
i++; | |
} | |
while (j < arr2.length) { | |
// do logic | |
j++; | |
} | |
return ans; | |
} | |
``` | |
Sliding window | |
```python3 | |
def fn(arr): | |
left = ans = curr = 0 | |
for right in range(len(arr)): | |
# do logic here to add arr[right] to curr | |
while WINDOW_CONDITION_BROKEN: | |
# remove arr[left] from curr | |
left += 1 | |
# update ans | |
return ans | |
``` | |
```javascript | |
let fn = arr => { | |
let left = 0, ans = 0, curr = 0; | |
for (let right = 0; right < arr.length; right++) { | |
// do logic here to add arr[right] to curr | |
while (WINDOW_CONDITION_BROKEN) { | |
// remove arr[left] from curr | |
left++; | |
} | |
// update ans | |
} | |
return ans; | |
} | |
``` | |
Build a prefix sum | |
```python3 | |
def fn(arr): | |
prefix = [arr[0]] | |
for i in range(1, len(arr)): | |
prefix.append(prefix[-1] + arr[i]) | |
return prefix | |
``` | |
```javascript | |
let fn = arr => { | |
let prefix = [arr[0]]; | |
for (let i = 1; i < arr.length; i++) { | |
prefix.push(prefix[prefix.length - 1] + arr[i]); | |
} | |
return prefix; | |
} | |
``` | |
Efficient string building | |
```python3 | |
# arr is a list of characters | |
def fn(arr): | |
ans = [] | |
for c in arr: | |
ans.append(c) | |
return "".join(ans) | |
``` | |
```javascript | |
// arr is a list of characters | |
let fn = arr => { | |
let ans = []; | |
for (const c of arr) { | |
ans.push(c); | |
} | |
return ans.join("") | |
} | |
let fn = arr => { | |
let ans = ""; | |
for (const c of arr) { | |
ans += c; | |
} | |
return ans; | |
} | |
``` | |
> In JavaScript, benchmarking shows that concatenation with += is faster than using .join(). | |
Linked list: fast and slow pointer | |
```python3 | |
def fn(head): | |
slow = head | |
fast = head | |
ans = 0 | |
while fast and fast.next: | |
# do logic | |
slow = slow.next | |
fast = fast.next.next | |
return ans | |
``` | |
```javascript | |
let fn = head => { | |
let slow = head; | |
let fast = head; | |
let ans = 0; | |
while (fast && fast.next) { | |
// do logic | |
slow = slow.next; | |
fast = fast.next.next; | |
} | |
return ans; | |
} | |
``` | |
Reversing a linked list | |
```python3 | |
def fn(head): | |
curr = head | |
prev = None | |
while curr: | |
next_node = curr.next | |
curr.next = prev | |
prev = curr | |
curr = next_node | |
return prev | |
``` | |
```javascript | |
let fn = head => { | |
let curr = head; | |
let prev = null; | |
while (curr) { | |
let nextNode = curr.next; | |
curr.next = prev; | |
prev = curr; | |
curr = nextNode; | |
} | |
return prev; | |
} | |
``` | |
Find number of subarrays that fit an exact criteria | |
```python3 | |
from collections import defaultdict | |
def fn(arr, k): | |
counts = defaultdict(int) | |
counts[0] = 1 | |
ans = curr = 0 | |
for num in arr: | |
# do logic to change curr | |
ans += counts[curr - k] | |
counts[curr] += 1 | |
return ans | |
``` | |
```javascript | |
let fn = (arr, k) => { | |
let counts = new Map(); | |
counts.set(0, 1); | |
let ans = 0, curr = 0; | |
for (const num of arr) { | |
// do logic to change curr | |
ans += counts.get(curr - k) || 0; | |
counts.set(curr, (counts.get(curr) || 0) + 1); | |
} | |
return ans; | |
} | |
``` | |
Monotonic increasing stack | |
The same logic can be applied to maintain a monotonic queue. | |
```python3 | |
def fn(arr): | |
stack = [] | |
ans = 0 | |
for num in arr: | |
# for monotonic decreasing, just flip the > to < | |
while stack and stack[-1] > num: | |
# do logic | |
stack.pop() | |
stack.append(num) | |
return ans | |
``` | |
```javascript | |
let fn = arr => { | |
let stack = []; | |
let ans = 0; | |
for (const num of arr) { | |
// for monotonic decreasing, just flip the > to < | |
while (stack.length && stack[stack.length - 1] > num) { | |
// do logic | |
stack.pop(); | |
} | |
stack.push(num); | |
} | |
return ans; | |
} | |
``` | |
Binary tree: DFS (recursive) | |
```python3 | |
def dfs(root): | |
if not root: | |
return | |
ans = 0 | |
# do logic | |
dfs(root.left) | |
dfs(root.right) | |
return ans | |
``` | |
```javascript | |
let dfs = root => { | |
if (!root) { | |
return; | |
} | |
let ans = 0; | |
// do logic | |
dfs(root.left); | |
dfs(root.right); | |
return ans; | |
} | |
``` | |
Binary tree: DFS (iterative) | |
```python3 | |
def dfs(root): | |
stack = [root] | |
ans = 0 | |
while stack: | |
node = stack.pop() | |
# do logic | |
if node.left: | |
stack.append(node.left) | |
if node.right: | |
stack.append(node.right) | |
return ans | |
``` | |
```javascript | |
let dfs = root => { | |
let stack = [root]; | |
let ans = 0; | |
while (stack.length) { | |
let node = stack.pop(); | |
// do logic | |
if (node.left) { | |
stack.push(node.left); | |
} | |
if (node.right) { | |
stack.push(node.right); | |
} | |
} | |
return ans; | |
} | |
``` | |
Binary tree: BFS | |
```python3 | |
from collections import deque | |
def fn(root): | |
queue = deque([root]) | |
ans = 0 | |
while queue: | |
current_length = len(queue) | |
# do logic for current level | |
for _ in range(current_length): | |
node = queue.popleft() | |
# do logic | |
if node.left: | |
queue.append(node.left) | |
if node.right: | |
queue.append(node.right) | |
return ans | |
``` | |
```javascript | |
let fn = root => { | |
let queue = [root]; | |
let ans = 0; | |
while (queue.length) { | |
let currentLength = queue.length; | |
// do logic for current level | |
let nextQueue = []; | |
for (let i = 0; i < currentLength; i++) { | |
let node = queue[i]; | |
// do logic | |
if (node.left) { | |
nextQueue.push(node.left); | |
} | |
if (node.right) { | |
nextQueue.push(node.right); | |
} | |
} | |
queue = nextQueue; | |
} | |
return ans; | |
} | |
``` | |
Graph: DFS (recursive) | |
For the graph templates, assume the nodes are numbered from 0 to n - 1 and the graph is given as an adjacency list. Depending on the problem, you may need to convert the input into an equivalent adjacency list before using the templates. | |
```python3 | |
def fn(graph): | |
def dfs(node): | |
ans = 0 | |
# do some logic | |
for neighbor in graph[node]: | |
if neighbor not in seen: | |
seen.add(neighbor) | |
ans += dfs(neighbor) | |
return ans | |
seen = {START_NODE} | |
return dfs(START_NODE) | |
``` | |
```javascript | |
let fn = graph => { | |
let dfs = node => { | |
let ans = 0; | |
// do some logic | |
for (const neighbor of graph[node]) { | |
if (!seen.has(neighbor)) { | |
seen.add(neighbor); | |
ans += dfs(neighbor); | |
} | |
} | |
return ans; | |
} | |
let seen = new Set([START_NODE]); | |
return dfs(START_NODE); | |
} | |
``` | |
Graph: DFS (iterative) | |
```python3 | |
def fn(graph): | |
stack = [START_NODE] | |
seen = {START_NODE} | |
ans = 0 | |
while stack: | |
node = stack.pop() | |
# do some logic | |
for neighbor in graph[node]: | |
if neighbor not in seen: | |
seen.add(neighbor) | |
stack.append(neighbor) | |
return ans | |
``` | |
```javascript | |
let fn = graph => { | |
let stack = [START_NODE]; | |
let seen = new Set([START_NODE]); | |
let ans = 0; | |
while (stack.length) { | |
let node = stack.pop(); | |
// do some logic | |
for (const neighbor of graph[node]) { | |
if (!seen.has(neighbor)) { | |
seen.add(neighbor); | |
stack.push(neighbor); | |
} | |
} | |
} | |
return ans; | |
} | |
``` | |
```python3 | |
from collections import deque | |
def fn(graph): | |
queue = deque([START_NODE]) | |
seen = {START_NODE} | |
ans = 0 | |
while queue: | |
node = queue.popleft() | |
# do some logic | |
for neighbor in graph[node]: | |
if neighbor not in seen: | |
seen.add(neighbor) | |
queue.append(neighbor) | |
return ans | |
``` | |
```javascript | |
let fn = graph => { | |
let queue = [START_NODE]; | |
let seen = new Set([START_NODE]); | |
let ans = 0; | |
while (queue.length) { | |
let currentLength = 0; | |
let nextQueue = []; | |
for (let i = 0; i < currentLength; i++) { | |
let node = queue[i]; | |
// do some logic | |
for (const neighbor of graph[node]) { | |
if (!seen.has(neighbor)) { | |
seen.add(neighbor); | |
nextQueue.push(neighbor); | |
} | |
} | |
} | |
queue = nextQueue; | |
} | |
return ans; | |
} | |
``` | |
Find top k elements with heap | |
```python | |
import heapq | |
def fn(arr, k): | |
heap = [] | |
for num in arr: | |
# do some logic to push onto heap according to problem's criteria | |
heapq.heappush(heap, (CRITERIA, num)) | |
if len(heap) > k: | |
heapq.heappop(heap) | |
return [num for num in heap] | |
``` | |
```javascript | |
/* | |
JavaScript does not have any built in support - it is recommended | |
that you have another language ready in case you need to use a heap | |
*/ | |
``` | |
soy | |
Binary search | |
```python3 | |
def fn(arr, target): | |
left = 0 | |
right = len(arr) - 1 | |
while left <= right: | |
mid = (left + right) // 2 | |
if arr[mid] == target: | |
# do something | |
return | |
if arr[mid] > target: | |
right = mid - 1 | |
else: | |
left = mid + 1 | |
# left is the insertion point | |
return left | |
``` | |
```javascript | |
let fn = (arr, target) => { | |
let left = 0; | |
let right = arr.length - 1; | |
while (left <= right) { | |
let mid = Math.floor((left + right) / 2); | |
if (arr[mid] == target) { | |
// do something | |
return; | |
} | |
if (arr[mid] > target) { | |
right = mid - 1; | |
} else { | |
left = mid + 1; | |
} | |
} | |
// left is the insertion point | |
return left; | |
} | |
``` | |
Binary search: duplicate elements, left-most insertion point | |
```python | |
def fn(arr, target): | |
left = 0 | |
right = len(arr) | |
while left < right: | |
mid = (left + right) // 2 | |
if arr[mid] >= target: | |
right = mid | |
else: | |
left = mid + 1 | |
return left | |
``` | |
```javascript | |
let fn = (arr, target) => { | |
let left = 0; | |
let right = arr.length; | |
while (left < right) { | |
let mid = Math.floor((left + right) / 2); | |
if (arr[mid] >= target) { | |
right = mid; | |
} else { | |
left = mid + 1; | |
} | |
} | |
return left; | |
} | |
``` | |
Binary search: duplicate elements, right-most insertion point | |
```python | |
def fn(arr, target): | |
left = 0 | |
right = len(arr) | |
while left < right: | |
mid = (left + right) // 2 | |
if arr[mid] > target: | |
right = mid | |
else: | |
left = mid + 1 | |
return left | |
``` | |
```javascript | |
let fn = (arr, target) => { | |
let left = 0; | |
let right = arr.length; | |
while (left < right) { | |
let mid = Math.floor((left + right) / 2); | |
if (arr[mid] > target) { | |
right = mid; | |
} else { | |
left = mid + 1; | |
} | |
} | |
return left; | |
} | |
``` | |
Binary search: for greedy problems | |
If looking for a minimum: | |
```python | |
def fn(arr): | |
def check(x): | |
# this function is implemented depending on the problem | |
return BOOLEAN | |
left = MINIMUM_POSSIBLE_ANSWER | |
right = MAXIMUM_POSSIBLE_ANSWER | |
while left <= right: | |
mid = (left + right) // 2 | |
if check(mid): | |
right = mid - 1 | |
else: | |
left = mid + 1 | |
return left | |
``` | |
```javascript | |
let fn = arr => { | |
let check = x => { | |
// this function is implemented depending on the problem | |
return BOOLEAN; | |
} | |
let left = MINIMUM_POSSIBLE_ANSWER; | |
let right = MAXMIMUM_POSSIBLE_ANSWER; | |
while (left <= right) { | |
let mid = Math.floor((left + right) / 2); | |
if (check(mid)) { | |
right = mid - 1; | |
} else { | |
left = mid + 1; | |
} | |
} | |
return left; | |
} | |
``` | |
If looking for a maximum: | |
```python | |
def fn(arr): | |
def check(x): | |
# this function is implemented depending on the problem | |
return BOOLEAN | |
left = MINIMUM_POSSIBLE_ANSWER | |
right = MAXIMUM_POSSIBLE_ANSWER | |
while left <= right: | |
mid = (left + right) // 2 | |
if check(mid): | |
left = mid + 1 | |
else: | |
right = mid - 1 | |
return right | |
``` | |
```javascript | |
let fn = arr => { | |
let check = x => { | |
// this function is implemented depending on the problem | |
return BOOLEAN; | |
} | |
let left = MINIMUM_POSSIBLE_ANSWER; | |
let right = MAXMIMUM_POSSIBLE_ANSWER; | |
while (left <= right) { | |
let mid = Math.floor((left + right) / 2); | |
if (check(mid)) { | |
left = mid + 1; | |
} else { | |
right = mid - 1; | |
} | |
} | |
return right; | |
} | |
``` | |
Backtracking | |
```python | |
def backtrack(curr, OTHER_ARGUMENTS...): | |
if (BASE_CASE): | |
# modify the answer | |
return | |
ans = 0 | |
for (ITERATE_OVER_INPUT): | |
# modify the current state | |
ans += backtrack(curr, OTHER_ARGUMENTS...) | |
# undo the modification of the current state | |
return ans | |
``` | |
```javascript | |
let backtrack = (curr, OTHER_ARGUMENTS...) => { | |
if (BASE_CASE) { | |
// modify the answer | |
return; | |
} | |
let ans = 0; | |
for (ITERATE_OVER_INPUT) { | |
// modify the current state | |
ans += backtrack(curr, OTHER_ARGUMENTS...); | |
// undo the modification of the current state | |
} | |
return ans; | |
} | |
``` | |
Dynamic programming: top-down memoization | |
```python | |
def fn(arr): | |
def dp(STATE): | |
if BASE_CASE: | |
return 0 | |
if STATE in memo: | |
return memo[STATE] | |
ans = RECURRENCE_RELATION(STATE) | |
memo[STATE] = ans | |
return ans | |
memo = {} | |
return dp(STATE_FOR_WHOLE_INPUT) | |
``` | |
```javascript | |
let fn = arr => { | |
let dp = STATE => { | |
if (BASE_CASE) { | |
return 0; | |
} | |
if (memo[STATE] != -1) { | |
return memo[STATE]; | |
} | |
let ans = RECURRENCE_RELATION(STATE); | |
memo[STATE] = ans; | |
return ans; | |
} | |
let memo = ARRAY_SIZED_ACCORDING_TO_STATE; | |
return dp(STATE_FOR_WHOLE_INPUT); | |
} | |
``` | |
Build a trie | |
```python3 | |
# note: using a class is only necessary if you want to store data at each node. | |
# otherwise, you can implement a trie using only hash maps. | |
class TrieNode: | |
def __init__(self): | |
# you can store data at nodes if you wish | |
self.data = None | |
self.children = {} | |
def fn(words): | |
root = TrieNode() | |
for word in words: | |
curr = root | |
for c in word: | |
if c not in curr.children: | |
curr.children[c] = TrieNode() | |
curr = curr.children[c] | |
# at this point, you have a full word at curr | |
# you can perform more logic here to give curr an attribute if you want | |
return root | |
``` | |
```javascript | |
// note: using a class is only necessary if you want to store data at each node. | |
// otherwise, you can implement a trie using only hash maps. | |
class TrieNode { | |
constructor() { | |
// you can store data at nodes if you wish | |
this.data = null; | |
this.children = new Map(); | |
} | |
} | |
let fn = words => { | |
let root = new TrieNode(); | |
for (const word of words) { | |
let curr = root; | |
for (const c of word) { | |
if (!curr.children.has(c)) { | |
curr.children.set(c, new TrieNode()); | |
} | |
curr = curr.children.get(c); | |
} | |
// at this point, you have a full word at curr | |
// you can perform more logic here to give curr an attribute if you want | |
} | |
return root; | |
} | |
``` | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment