DSA Language Cheatsheet
Quick-reference for DSA interview rounds across JavaScript, TypeScript, Go, and Python 3.
Core ops: declare, init with size, slice/subarray, sort, reverse, two-pointer setup.
JavaScript
TypeScript
Go
Python 3
Declare / init
const a = [1,2,3];
const z = new Array(5).fill(0);const a: number[] = [1,2,3];
const z = new Array<number>(5).fill(0);a := []int{1,2,3}
z := make([]int, 5) // all 0a = [1, 2, 3]
z = [0] * 5Append / push
a.push(4);
a.unshift(0); // front O(n)a.push(4);
a.unshift(0); // front O(n)a = append(a, 4)
// prepend:
a = append([]int{0}, a...)a.append(4)
a.insert(0, 0) # front O(n)Slice / subarray
a.slice(1, 3) // [1,3) copy
a.splice(1, 2) // mutatesa.slice(1, 3) // [1,3) copy
a.splice(1, 2) // mutatesa[1:3] // view, shares mem
append([]int{}, a[1:3]...) // copya[1:3] # copy
a[::-1] # reversed copySort
a.sort((x,y)=>x-y); // nums
a.sort(); // LEXICOGRAPHIC!a.sort((x,y)=>x-y);
// same pitfall as JS!sort.Ints(a)
sort.Slice(a, func(i,j int) bool {
return a[i] < a[j] })a.sort() # in-place
sorted(a) # new list
a.sort(key=lambda x: -x)Two-pointer template
let l=0, r=a.length-1;
while(l<r){
// logic
l++; r--;
}let l=0, r=a.length-1;
while(l<r){
// logic
l++; r--;
}l, r := 0, len(a)-1
for l < r {
// logic
l++; r--
}l, r = 0, len(a)-1
while l < r:
# logic
l += 1; r -= 1String → char array & back
[..."hello"] // array
arr.join("") // back[..."hello"] // string[]
arr.join("") // back[]rune("hello") // unicode
[]byte("hello") // ASCII
string(arr) // backlist("hello") # list of chars
"".join(arr) # back to strFrequency count, visited set, and existence check are the most common interview patterns.
JavaScript
TypeScript
Go
Python 3
Create map / dict
const m = new Map();
const obj = {}; // plain objconst m = new Map<string,number>();
const obj: Record<string,number> = {};m := make(map[string]int)
m := map[string]int{"a":1}m = {}
m = {"a": 1}Get / set / delete
m.get(k); m.set(k,v);
m.delete(k); m.has(k);m.get(k); m.set(k,v);
m.delete(k); m.has(k);v := m[k] // 0 if missing
v, ok := m[k] // safe check
delete(m, k)m[k]; m[k]=v; del m[k]
m.get(k, default) # safeFrequency counter
const freq = new Map();
for (const x of arr)
freq.set(x,(freq.get(x)??0)+1);const freq = new Map<number,number>();
for (const x of arr)
freq.set(x,(freq.get(x)??0)+1);freq := make(map[int]int)
for _, v := range arr {
freq[v]++
}from collections import Counter
freq = Counter(arr)
freq[x] += 1 # auto-init 0Set operations
const s = new Set([1,2,3]);
s.add(4); s.has(2);
s.delete(2);const s = new Set<number>([1,2]);
s.add(4); s.has(2);
s.delete(2);// use map[T]bool or map[T]struct{}
seen := make(map[int]bool)
seen[x] = true
_, ok := seen[x]s = {1, 2, 3}
s.add(4); 2 in s;
s.discard(2)Iterate map
for (const [k,v] of m) {}
m.forEach((v,k) => {})for (const [k,v] of m) {}
// Object.entries(obj) for plainfor k, v := range m {
// order NOT guaranteed
}for k, v in m.items(): ...
for k in m: ... # keys onlyStack = LIFO. Queue = FIFO. JS/TS array
shift() is O(n) — avoid for queues. Python deque is the correct choice.JavaScript
TypeScript
Go
Python 3
Stack (LIFO)
const stk = [];
stk.push(x); // O(1)
stk.pop(); // O(1)
stk[stk.length-1]; // peekconst stk: number[] = [];
stk.push(x);
stk.pop();
stk.at(-1); // peekstk := []int{}
stk = append(stk, x)
top := stk[len(stk)-1]
stk = stk[:len(stk)-1] // popstk = []
stk.append(x) # push O(1)
stk.pop() # O(1)
stk[-1] # peekQueue (FIFO)
// array.shift() is O(n)!
const q = [];
q.push(x); // enqueue
q.shift(); // dequeue O(n) ⚠// same O(n) caveat
const q: number[] = [];
q.push(x);
q.shift(); // O(n) ⚠q := []int{}
q = append(q, x) // enqueue
front := q[0]
q = q[1:] // dequeuefrom collections import deque
q = deque()
q.append(x) # O(1)
q.popleft() # O(1) ✓Monotonic stack pattern
const stk = [];
for (const x of arr) {
while(stk.length && stk.at(-1) > x)
stk.pop();
stk.push(x);
}const stk: number[] = [];
for (const x of arr) {
while(stk.length && stk.at(-1)! > x)
stk.pop();
stk.push(x);
}stk := []int{}
for _, x := range arr {
for len(stk)>0 && stk[len(stk)-1]>x {
stk = stk[:len(stk)-1]
}
stk = append(stk, x)
}stk = []
for x in arr:
while stk and stk[-1] > x:
stk.pop()
stk.append(x)JS/TS have no built-in heap — write a class or use the negate trick with a MinHeap. Python
heapq and Go's container/heap are min-heaps natively.JavaScript
TypeScript
Go
Python 3
Min-heap push / pop
// No built-in. Minimal class:
class MinHeap {
push(v) { /* sift up */ }
pop() { /* sift down */ }
peek() { return this.h[0] }
}class MinHeap<T> {
constructor(private cmp:
(a:T,b:T)=>number) {}
push(v:T) { /* ... */ }
pop(): T { /* ... */ }
}import "container/heap"
// implement heap.Interface:
// Len, Less, Swap, Push, Pop
heap.Push(&h, x)
heap.Pop(&h)import heapq
h = []
heapq.heappush(h, x)
x = heapq.heappop(h)
h[0] # peek minMax-heap trick
// Negate → use MinHeap
heap.push(-x);
const max = -heap.pop();// same negate trick
heap.push(-x);
const max = -heap.pop();// flip Less: a[i] > a[j]
// or negate values before Push# negate for max-heap
heapq.heappush(h, -x)
max_val = -heapq.heappop(h)Heapify existing array
// O(n log n) — push each
arr.forEach(x => h.push(x));// same O(n log n)h := append(IntHeap(nil), arr...)
heap.Init(&h) // O(n)heapq.heapify(arr) # O(n)
# modifies in-placeTop-K pattern
for (const x of arr) {
h.push(x);
if (h.size() > k) h.pop();
}
// heap has top-k elementsfor (const x of arr) {
h.push(x);
if (h.size() > k) h.pop();
}for _, x := range arr {
heap.Push(&h, x)
if h.Len() > k {
heap.Pop(&h)
}
}# simplest way
heapq.nlargest(k, arr)
heapq.nsmallest(k, arr)Dummy head eliminates edge cases. Fast/slow pointer detects cycles and finds midpoints. Always track
prev for in-place reversal.JavaScript
TypeScript
Go
Python 3
Node definition
class ListNode {
constructor(val=0, next=null) {
this.val=val;
this.next=next;
}
}class ListNode {
constructor(
public val=0,
public next: ListNode|null=null
) {}
}type ListNode struct {
Val int
Next *ListNode
}class ListNode:
def __init__(self,
val=0, nxt=None):
self.val = val
self.next = nxtReverse in-place
let prev=null, cur=head;
while(cur){
let nxt=cur.next;
cur.next=prev;
prev=cur; cur=nxt;
}
return prev;let prev: ListNode|null=null;
let cur=head;
while(cur){
const nxt=cur.next;
cur.next=prev; prev=cur; cur=nxt;
}
return prev;var prev *ListNode
cur := head
for cur != nil {
nxt := cur.Next
cur.Next = prev
prev = cur; cur = nxt
}
return prevprev, cur = None, head
while cur:
nxt = cur.next
cur.next = prev
prev, cur = cur, nxt
return prevFast / slow pointer
let slow=head, fast=head;
while(fast&&fast.next){
slow=slow.next;
fast=fast.next.next;
}
// slow = midpointlet slow=head, fast=head;
while(fast?.next){
slow=slow!.next!;
fast=fast.next.next;
}
// slow = midpointslow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
// slow = midpointslow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# slow = midpointDummy head pattern
const dummy = new ListNode(0);
dummy.next = head;
let cur = dummy;
// build / modify ...
return dummy.next;const dummy = new ListNode(0);
dummy.next = head;
let cur: ListNode = dummy;
return dummy.next;dummy := &ListNode{}
dummy.Next = head
cur := dummy
// ...
return dummy.Nextdummy = ListNode(0)
dummy.next = head
cur = dummy
# ...
return dummy.nextBFS for shortest path / level-order. DFS for path/subtree problems. Use iterative DFS for deep trees to avoid stack overflow.
JavaScript
TypeScript
Go
Python 3
Tree node
class TreeNode {
constructor(val=0,
left=null, right=null) {
this.val=val;
this.left=left; this.right=right;
}
}class TreeNode {
constructor(public val=0,
public left:TreeNode|null=null,
public right:TreeNode|null=null
){}
}type TreeNode struct {
Val int
Left, Right *TreeNode
}class TreeNode:
def __init__(self, val=0,
left=None, right=None):
self.val=val
self.left=left; self.right=rightDFS inorder (iterative)
const stk=[], res=[];
let cur=root;
while(cur||stk.length){
while(cur){stk.push(cur);cur=cur.left;}
cur=stk.pop();res.push(cur.val);
cur=cur.right;
}const stk:TreeNode[]=[];
let cur:TreeNode|null=root;
while(cur||stk.length){
while(cur){stk.push(cur);cur=cur.left;}
cur=stk.pop()!;res.push(cur.val);
cur=cur.right;
}stk := []*TreeNode{}; cur := root
for cur != nil || len(stk) > 0 {
for cur != nil {
stk = append(stk, cur); cur = cur.Left }
n := len(stk)-1
cur = stk[n]; stk = stk[:n]
res = append(res, cur.Val); cur = cur.Right
}stk, cur, res = [], root, []
while cur or stk:
while cur:
stk.append(cur); cur = cur.left
cur = stk.pop()
res.append(cur.val); cur = cur.rightBFS level-order
const q=[root];
while(q.length){
const node=q.shift();
if(node.left) q.push(node.left);
if(node.right) q.push(node.right);
}const q=[root];
while(q.length){
const node=q.shift()!;
if(node.left) q.push(node.left);
if(node.right) q.push(node.right);
}q := []*TreeNode{root}
for len(q) > 0 {
node := q[0]; q = q[1:]
if node.Left != nil { q = append(q, node.Left) }
if node.Right != nil { q = append(q, node.Right) }
}from collections import deque
q = deque([root])
while q:
node = q.popleft()
if node.left: q.append(node.left)
if node.right: q.append(node.right)Adjacency list + visited
const g = new Map();
g.set(u, [...(g.get(u)??[]), v]);
const vis = new Set();const g = new Map<number,number[]>();
const vis = new Set<number>();g := make(map[int][]int)
g[u] = append(g[u], v)
vis := make(map[int]bool)from collections import defaultdict
g = defaultdict(list)
g[u].append(v)
vis = set()Binary search invariant: what does
lo always satisfy? What does hi always satisfy? The answer is lo when the loop ends.JavaScript
TypeScript
Go
Python 3
Binary search (exact)
let lo=0, hi=n-1;
while(lo<=hi){
const mid=(lo+hi)>>1;
if(a[mid]===t) return mid;
else if(a[mid]<t) lo=mid+1;
else hi=mid-1;
}let lo=0, hi=n-1;
while(lo<=hi){
const mid=(lo+hi)>>1;
if(a[mid]===t) return mid;
else if(a[mid]<t) lo=mid+1;
else hi=mid-1;
}lo, hi := 0, len(a)-1
for lo <= hi {
mid := (lo + hi) >> 1
if a[mid] == t { return mid }
else if a[mid] < t { lo = mid+1 }
else { hi = mid-1 }
}import bisect
# use bisect_left for left-bound
lo, hi = 0, len(a)-1
while lo <= hi:
mid = (lo+hi)>>1
if a[mid]==t: return mid
elif a[mid]<t: lo=mid+1
else: hi=mid-1Left-bound (first ≥ target)
let lo=0, hi=n;
while(lo<hi){
const mid=(lo+hi)>>1;
if(a[mid]<t) lo=mid+1;
else hi=mid;
}
// lo = first index >= tlet lo=0, hi=n;
while(lo<hi){
const mid=(lo+hi)>>1;
if(a[mid]<t) lo=mid+1;
else hi=mid;
}lo, hi := 0, len(a)
for lo < hi {
mid := (lo+hi) >> 1
if a[mid] < t { lo = mid+1 }
else { hi = mid }
}
// or: sort.SearchInts(a, t)bisect.bisect_left(a, t)
# leftmost i s.t. a[i] >= t
bisect.bisect_right(a, t)
# leftmost i s.t. a[i] > tCustom sort comparator
arr.sort((a,b) => {
if(a.x !== b.x) return a.x-b.x;
return b.y-a.y; // desc y
});arr.sort((a,b): number => {
if(a.x !== b.x) return a.x-b.x;
return b.y-a.y;
});sort.Slice(arr, func(i,j int) bool {
if arr[i].X != arr[j].X {
return arr[i].X < arr[j].X
}
return arr[i].Y > arr[j].Y
})from functools import cmp_to_key
arr.sort(key=lambda x: (x.x, -x.y))
# tuple key: primary asc, secondary desc
# cmp_to_key for complex 3-way compareDefine: state, transition, base case, answer location. Top-down is easier to write; bottom-up avoids recursion depth limits.
JavaScript
TypeScript
Go
Python 3
Top-down memo
const memo = new Map();
function dp(i) {
if(memo.has(i)) return memo.get(i);
const res = /* recurrence */;
memo.set(i, res);
return res;
}const memo = new Map<number,number>();
function dp(i: number): number {
if(memo.has(i)) return memo.get(i)!;
const res = /* ... */;
memo.set(i, res); return res;
}memo := make(map[int]int)
var dp func(int) int
dp = func(i int) int {
if v, ok := memo[i]; ok { return v }
res := /* ... */
memo[i] = res; return res
}from functools import lru_cache
@lru_cache(maxsize=None)
def dp(i):
if base_case: return ...
return # recurrenceBottom-up 1D
const dp = new Array(n+1).fill(0);
dp[0] = 1; // base case
for(let i=1;i<=n;i++)
dp[i] = dp[i-1] + dp[i-2];const dp: number[] = new Array(n+1).fill(0);
dp[0] = 1;
for(let i=1;i<=n;i++)
dp[i] = dp[i-1] + dp[i-2];dp := make([]int, n+1)
dp[0] = 1
for i := 1; i <= n; i++ {
dp[i] = dp[i-1] + dp[i-2]
}dp = [0] * (n + 1)
dp[0] = 1
for i in range(1, n + 1):
dp[i] = dp[i-1] + dp[i-2]2D DP (knapsack / LCS)
const dp = Array.from({length:m+1},
() => new Array(n+1).fill(0));
for(let i=1;i<=m;i++)
for(let j=1;j<=n;j++)
dp[i][j] = /* transition */;const dp:number[][] = Array.from(
{length:m+1},()=>new Array(n+1).fill(0));
for(let i=1;i<=m;i++)
for(let j=1;j<=n;j++) {}dp := make([][]int, m+1)
for i := range dp {
dp[i] = make([]int, n+1)
}
for i:=1;i<=m;i++ {
for j:=1;j<=n;j++ {} }dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(1, m+1):
for j in range(1, n+1):
dp[i][j] = ...Infinity init
dp.fill(Infinity); // min problems
dp.fill(-Infinity); // max problemsdp.fill(Infinity);
dp.fill(-Infinity);import "math"
math.MaxInt math.MinInt
// or: 1<<60 and -(1<<60)dp = [float('inf')] * n
dp = [float('-inf')] * nLanguage-specific gotchas that cost time in interviews. Know these cold.
JavaScript pitfalls
// Sort is LEXICOGRAPHIC by default!
[10,9,1].sort() // [1,10,9] WRONG
[10,9,1].sort((a,b)=>a-b) // [1,9,10] ✓
// Integer division
7 / 2 // 3.5 (not 3!)
Math.floor(7/2) // 3
(7/2)|0 // 3 (bitwise)
// Char codes
"a".charCodeAt(0) // 97
String.fromCharCode(97) // "a"
TypeScript extras
// Non-null assertion when sure
arr.pop()! // T, not T|undefined
// as const for literal tuple types
const dirs = [[-1,0],[1,0]] as const
// Tuple key pitfall in Map!
// [1,2] !== [1,2] — use "1,2" string
const key = `${r},${c}`
// Readonly prevents accidental mutation
function f(a: Readonly<number[]>) {}
Go gotchas
// Slice is a VIEW — copy if needed
b := make([]int, len(a))
copy(b, a)
// Missing map key returns zero value
v, ok := m[k] // always use 2-val form
// No built-in min/max for ints
if a > b { return a }; return b
// String concat in loop → Builder
var sb strings.Builder
sb.WriteString(s)
result := sb.String()
Python power moves
# No integer overflow (arbitrary precision)
# float('inf') works in min() / max()
# Tuple as hashable set/dict key
seen.add((r, c))
# Swap without temp variable
a, b = b, a
# Zip for matrix transpose
list(zip(*matrix))
# enumerate + tuple unpacking
for i, v in enumerate(arr): ...
# defaultdict avoids KeyError
from collections import defaultdict
Complexity quick-ref
| Operation | JS / TS | Go | Python |
|---|---|---|---|
| Array push / pop | O(1) amort | O(1) amort | O(1) amort |
| Array shift (front) | O(n) ⚠ | O(n) ⚠ | deque O(1) |
| Map get / set | O(1) avg | O(1) avg | O(1) avg |
| Sort | O(n log n) | O(n log n) | O(n log n) |
| Heap push / pop | O(log n) | O(log n) | O(log n) |
| Binary search | O(log n) | O(log n) | O(log n) |