Go for Coding Interviews: The Standard Library Cheat Sheet

May 26, 202610 min read
interview-prepdsaalgorithmscareer
Go for Coding Interviews: The Standard Library Cheat Sheet
TL;DR
  • Go's slice header passes by value but shares the backing array -- always use append([]int{}, path...) to copy before storing in backtracking output
  • Nil map writes panic at runtime, not compile time; always initialize with make(map[K]V) before writing
  • container/heap requires five interface methods to use; memorize the MinHeap skeleton before interview day
  • No built-in set in Go -- use map[K]struct{} instead of map[K]bool since the empty struct costs zero bytes
  • Map iteration order is randomized by design; collect keys into a slice and sort before any ordered traversal
  • Integer overflow is silent in Go; use math.MaxInt and math.MinInt as sentinels rather than magic numbers
  • slices.SortFunc (Go 1.21+) takes an int comparator instead of a bool, and is generally faster than sort.Slice

Go is a legitimate interview language at most major tech companies. The problem is that it ships with a lean standard library, and you will spend real interview minutes implementing things Python gives you for free. Python has a heap. Python has a set. Python has sorted containers from a third-party library one import away. Go has a container/heap that requires you to implement five methods before you can touch it. This is the precise map: what's available, what's missing, and where the traps are.

Should You Actually Use Go?

Use it if you write Go professionally or if the role is explicitly Go-based. At Cloudflare, Datadog, HashiCorp, Uber infrastructure teams, and most SRE and platform roles, Go is a first-class interview language and sometimes the expected one. At pure product companies, Python will almost always save you time.

Go's biggest interview advantage is that it forces clarity. There is no list comprehension magic, no implicit type coercion, no dynamic typing hiding what's actually happening. When you reason about an algorithm in Go, the interviewer sees exactly what you're thinking. That works in your favor when your thinking is good.

The cost: no built-in set, no built-in heap with a clean API, no ordered map. You will write boilerplate. Budget for it.

Slices: The Thing That Looks Like an Array

A Go slice is a three-field header pointing at an underlying array: pointer, length, capacity. When you pass a slice to a function, you pass the header by value. The backing array is shared until an append triggers a reallocation. This is the kind of design decision that makes total sense in a systems language and causes interview bugs at 3am.

// make([]T, len, cap) nums := make([]int, 0, 10) // length 0, capacity 10, no allocation yet nums = append(nums, 1, 2, 3) // Gotcha: subslice shares backing array a := []int{1, 2, 3, 4, 5} b := a[1:3] // shares a's memory b = append(b, 99) // overwrites a[3], not what you expected

For interview problems involving DFS paths or combinations, copy your slice before storing it:

path = append(path, val) result = append(result, append([]int{}, path...)) // copy, not reference path = path[:len(path)-1]

The append([]int{}, path...) idiom is the Go equivalent of Python's path[:]. Miss this and your backtracking output will contain garbage. Every case. Every time.

Maps: Safe to Read, Deadly to Write Uninitialized

Two things will bite you in a timed interview.

First: writing to a nil map panics at runtime, not compile time.

var m map[string]int m["key"]++ // panic: assignment to entry in nil map m := make(map[string]int) // correct m["key"]++ // fine

Reading from a nil map is safe and returns the zero value. Writing is a panic. The compiler does not warn you. The tests don't catch it unless you hit that code path. The interviewer will watch you stare at a stack trace for ninety seconds.

Go panic: PANIC → Panik, panic: PANIC [recovered] → Kalm, panic: PANIC [recovered, repanicked] → Panik

Go's panic recovery model, illustrated by the language's own error messages.

Second: map iteration order is randomized by design. Go randomizes map traversal between runs. If your solution depends on traversal order, collect the keys into a slice and sort it.

Check for key existence with the two-value form:

val, ok := m[key] if !ok { // key not present }

Using just val := m[key] returns 0 for missing int keys. That will produce wrong answers on problems where 0 is a valid map entry.

Strings: Bytes vs Runes

len(s) counts bytes, not characters. For ASCII problems (the vast majority of LeetCode) this does not matter. For Unicode problems, it matters a lot.

s := "hello" len(s) // 5 bytes, 5 chars (ASCII) s2 := "日本語" len(s2) // 9 bytes (3 UTF-8 chars, 3 bytes each) len([]rune(s2)) // 3 runes

range over a string iterates by rune, not byte:

for i, r := range "hello" { // i = byte index, r = rune value }

For any problem involving character frequency or manipulation, convert to []byte (ASCII) or []rune (Unicode) first. Strings in Go are immutable, so building one in a loop via += is O(n²). Use strings.Builder instead:

var sb strings.Builder for _, ch := range chars { sb.WriteByte(ch) } result := sb.String()

Sorting: Old API vs New

Go has two sorting layers. You should know both.

The old sort package works on everything but requires more boilerplate:

sort.Ints(nums) // in-place ascending sort.Strings(strs) // in-place lexicographic sort.Slice(people, func(i, j int) bool { // custom comparator, NOT stable return people[i].Age < people[j].Age }) sort.SliceStable(people, func(i, j int) bool { // stable version return people[i].Age < people[j].Age })

The slices package (Go 1.21+) is cleaner and generally faster:

import "slices" slices.Sort(nums) // works for any ordered type slices.SortFunc(people, func(a, b Person) int { return a.Age - b.Age // negative = a before b }) found, idx := slices.BinarySearch(sorted, target)

For binary search with the old API, sort.Search(n, f) returns the smallest index where f(i) is true. The function must be monotonic (false...false...true...true). It does not tell you if the value was found; you have to check:

idx := sort.SearchInts(sorted, target) if idx < len(sorted) && sorted[idx] == target { // found }

Using slices.Sort signals you know modern Go. Using sort.Ints is not wrong, it just shows an older mental model.

The Three Things Go Is Missing

No Set

Use map[K]struct{}. The empty struct occupies zero bytes, unlike map[K]bool which wastes one byte per entry. In a set with millions of keys that adds up.

seen := make(map[int]struct{}) seen[val] = struct{}{} if _, ok := seen[val]; ok { // val is in the set }

No Priority Queue (Without Boilerplate)

container/heap gives you a heap, but you have to implement five methods before you can use it. Five. This is the most common Go interview stumbling block. Memorize this skeleton before your interview or you will spend ten minutes on the scaffolding instead of the problem.

import "container/heap" // MinHeap: smallest element at root type MinHeap []int func (h MinHeap) Len() int { return len(h) } func (h MinHeap) Less(i, j int) bool { return h[i] < h[j] } // flip to > for max-heap func (h MinHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *MinHeap) Push(x any) { *h = append(*h, x.(int)) } func (h *MinHeap) Pop() any { old := *h n := len(old) val := old[n-1] *h = old[:n-1] return val } // Usage: h := &MinHeap{3, 1, 4, 1, 5} heap.Init(h) heap.Push(h, 2) min := heap.Pop(h).(int)

The Less method controls the order. h[i] < h[j] gives min-heap, h[i] > h[j] gives max-heap. Change the element type and update Less to make it a heap of structs.

Push and Pop use pointer receivers because they change the slice length. The any type assertion in Pop is unavoidable. Forgetting the assertion gives you a compile error; getting the type wrong gives you a panic. In an interview. With someone watching.

No Ordered Map (TreeMap)

Go has no built-in equivalent of Java's TreeMap or C++'s std::map. For sorted key access, your options are:

  1. Collect keys, sort the slice, iterate in order (simple, O(n log n) per query)
  2. Maintain a sorted slice with sort.Search (O(log n) lookup, O(n) insertion)
  3. A third-party balanced BST (unlikely to be available in a contest environment)

Most problems that look like they need a TreeMap can be solved with a sorted slice. Reach for that first.

Five Gotchas That Cost People Problems

1. Integer overflow is silent. Go does not panic on int overflow. On 64-bit machines int is 64 bits, which covers most problems. Use math.MaxInt and math.MinInt for sentinel values. If a problem involves multiplying large numbers, check whether int64 is enough or switch to math/big.

2. sort.Slice is not stable. Use sort.SliceStable when equal elements must preserve their original order.

3. Closing over a loop variable in a goroutine. Classic concurrency trap:

// Wrong: all goroutines see the same i for i := 0; i < 5; i++ { go func() { fmt.Println(i) }() } // Correct: pass i as an argument for i := 0; i < 5; i++ { go func(n int) { fmt.Println(n) }(i) }

4. Appending to a subslice corrupts the parent. Covered above. If you slice and then append, copy first. Yes, even in an interview. Especially in an interview.

5. container/heap.Pop returns any. You must type-assert the result. heap.Pop(h).(int) not heap.Pop(h). Forgetting the assertion gives you a compile error; getting the type wrong gives you a panic. The interviewer will see both.

When Go Actually Wins

Concurrency problems. If the question involves producers and consumers, rate limiters, worker pools, or parallel computation, Go's goroutines and channels let you write a clear, correct solution in fewer lines than any other language that can do it correctly.

// Buffered channel as a semaphore (rate limiting concurrency) sem := make(chan struct{}, maxConcurrent) for _, task := range tasks { sem <- struct{}{} go func(t Task) { defer func() { <-sem }() process(t) }(task) }

For concurrency-heavy system design coding questions, Go's model is genuinely cleaner than Java's synchronized blocks or Python's GIL workarounds. This is where all the boilerplate tax pays off.

Quick Reference

NeedGo approach
Dynamic array[]T, append
Stack[]T, append/slice
Queue (simple)[]T with head index pointer
Setmap[T]struct{}
Min-heapcontainer/heap with Less: i < j
Max-heapcontainer/heap with Less: i > j
Sort ascendingslices.Sort(s) or sort.Ints(s)
Sort customslices.SortFunc or sort.Slice
Binary searchslices.BinarySearch or sort.SearchInts
String builderstrings.Builder
Char frequencymap[rune]int or [26]int for ASCII
Infinity sentinelmath.MaxInt, math.MinInt
Existence checkval, ok := m[key]

How to Prepare for Go Coding Interviews

The container/heap boilerplate has to be in muscle memory before interview day. Mock interviews in your target language under time pressure reveal gaps that silent problem-grinding never does. SpaceComplexity runs voice-based DSA interviews with rubric feedback, so you find out whether your verbal explanation of a Go priority queue lands before the real interview.

If you're still deciding which language to use, Best Language for Coding Interviews covers the data-driven breakdown. If you're committed to Go, pair this guide with heap data structures to understand what container/heap is actually doing, and read Java for Coding Interviews for a comparison with a richer standard library.

Further Reading