Go Coding Interview Cheat Sheet — Complete Syntax & Patterns Guide
A practical, no-fluff guide to the Go syntax, built-ins, and patterns you’ll actually reach for during a live coding interview.
Why Go for Coding Interviews?
Go is gaining ground fast in technical interviews, especially at infrastructure-heavy companies like Google, Cloudflare, Uber, and Dropbox. Its simplicity is a genuine advantage — no generics maze, no inheritance hierarchy, no implicit magic. But that simplicity cuts both ways: Go’s standard library is lean, which means you need to know exactly what’s available and when to roll your own.
The biggest adjustment for candidates coming from Python or Java is that Go has no built-in set, no built-in heap interface that’s plug-and-play, and sorts require implementing an interface or using a comparator func. Once you know these gaps and how to fill them, Go becomes a clean, fast, interview-friendly language.
If you're building your full preparation plan, start with our How to Prepare for a Coding Interview guide. This also pairs perfectly with Data Structures for Coding Interviews.
Looking for a different language? Python, Java, C++, JavaScript.
Already know why Go? Try a free Go mock interview on Intervu →
1. Data Types & Variables
package main
import "fmt"
func main() {
// Basic types
var x int = 10
var f float64 = 3.14
var b bool = true
var s string = "hello"
// Short declaration (most common in practice)
x := 10
pi := 3.14159
ok := true
// Integer types
var i8 int8 // -128 to 127
var i32 int32 // ~2.1 billion
var i64 int64 // ~9.2 × 10^18
var n int // platform-size (64-bit on modern systems)
// Unsigned
var u uint
var u32 uint32
// Constants
const MOD = 1_000_000_007
const INF = int(^uint(0) >> 1) // max int
const INF32 = 1<<31 - 1 // max int32
// Multiple assignment
a, b, c := 1, 2, 3
a, b = b, a // swap
// Zero values (Go initializes everything)
var zi int // 0
var zf float64 // 0.0
var zb bool // false
var zs string // ""
// Type conversion (explicit — no implicit casting)
i := 42
f2 := float64(i)
u2 := uint(f2)
s2 := string(rune(65)) // "A" — convert int to char
// Infinity proxies for interviews
posInf := math.MaxInt
negInf := math.MinInt
// or use math.Inf(1) / math.Inf(-1) for float64
}
Key tip: Go has no implicit type conversion. int32(x) + int64(y) is a compile error — you must cast explicitly. In interviews, stick to plain int unless the problem specifically requires 64-bit precision, then use int64 consistently.
2. Strings & Runes
import (
"strings"
"strconv"
"unicode"
)
s := "hello world"
// Basics
len(s) // 11 (bytes, not runes!)
s[0] // 104 ('h' as byte)
string(s[0]) // "h"
s[1:5] // "ello" [start, end)
s[6:] // "world"
s[:5] // "hello"
// Strings package
strings.ToUpper(s) // "HELLO WORLD"
strings.ToLower(s) // "hello world"
strings.TrimSpace(s) // remove leading/trailing whitespace
strings.Trim(s, "hd") // trim chars in cutset from both ends
strings.TrimLeft(s, "h")
strings.TrimRight(s, "d")
strings.Contains(s, "world") // true
strings.HasPrefix(s, "hel") // true
strings.HasSuffix(s, "rld") // true
strings.Index(s, "world") // 6 (-1 if not found)
strings.LastIndex(s, "l") // 9
strings.Count(s, "l") // 3
strings.Replace(s, "l", "r", -1) // replace all (-1 = all)
strings.Replace(s, "l", "r", 1) // replace first occurrence only
strings.Split(s, " ") // ["hello", "world"]
strings.Join([]string{"a","b","c"}, ",") // "a,b,c"
strings.Repeat("ab", 3) // "ababab"
strings.Fields(s) // split by any whitespace
// strconv — type conversions
strconv.Itoa(42) // int → "42"
strconv.Atoi("42") // "42" → 42, error
n, err := strconv.Atoi("123")
strconv.FormatInt(255, 16) // int64 → hex string "ff"
strconv.ParseInt("ff", 16, 64) // hex string → int64
// Runes — for Unicode-correct character iteration
for i, r := range s {
fmt.Println(i, r, string(r)) // byte index, rune value, char
}
runes := []rune(s) // string → rune slice (Unicode-safe)
runes[0] // first character as rune
string(runes) // rune slice → string
// Char checks (use unicode package)
unicode.IsLetter(r)
unicode.IsDigit(r)
unicode.IsUpper(r)
unicode.IsLower(r)
unicode.ToUpper(r)
unicode.ToLower(r)
// Byte-level char check (ASCII only — fine for most interview problems)
r >= 'a' && r <= 'z' // is lowercase letter
r >= '0' && r <= '9' // is digit
r - 'a' // distance from 'a' (0 for 'a', 25 for 'z')
int(r - '0') // digit char → int value
// Build string efficiently
var sb strings.Builder
sb.WriteString("hello")
sb.WriteByte(' ')
sb.WriteRune('W')
sb.WriteString("orld")
sb.String() // "hello World"
// String → byte slice and back
b := []byte(s)
b[0] = 'H'
string(b) // "Hello world"
Key tip: len(s) returns the number of bytes, not characters. For ASCII problems this is fine. For Unicode, convert to []rune first: runes := []rune(s) then len(runes). In most coding interviews, inputs are ASCII, so len(s) and s[i] are safe.
3. Arrays & Slices
Slices are Go’s primary sequence type and what you’ll use in almost every interview problem.
// Array (fixed size — rarely used directly)
arr := [5]int{3, 1, 4, 1, 5}
arr[0] // 3
len(arr) // 5
// Slice (dynamic — use this)
s := []int{3, 1, 4, 1, 5}
s2 := make([]int, 10) // len=10, cap=10, all zeros
s3 := make([]int, 0, 10) // len=0, cap=10 (pre-allocated)
// Access
s[0] // 3
s[len(s)-1] // 5 (last element)
s[1:4] // [1, 4, 1] [start, end)
s[:3] // [3, 1, 4]
s[2:] // [4, 1, 5]
// Append
s = append(s, 9) // [3, 1, 4, 1, 5, 9]
s = append(s, 7, 8) // append multiple
s = append(s, other...) // append another slice
// Length and capacity
len(s) // number of elements
cap(s) // allocated capacity
// Copy
dst := make([]int, len(s))
copy(dst, s) // copy(dst, src) — returns bytes copied
// 2D slice
matrix := make([][]int, rows)
for i := range matrix {
matrix[i] = make([]int, cols)
}
// Initialize with values
ones := make([]int, n)
for i := range ones { ones[i] = 1 }
// Fill
for i := range s { s[i] = -1 }
// Iterate
for i, v := range s {
fmt.Println(i, v)
}
for i := range s { } // index only
for _, v := range s { } // value only
// Reverse
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
// Contains (no built-in — linear scan or use map)
func contains(s []int, val int) bool {
for _, v := range s {
if v == val { return true }
}
return false
}
// Remove element at index i (order-preserving — O(n))
s = append(s[:i], s[i+1:]...)
// Remove element at index i (swap with last — O(1), changes order)
s[i] = s[len(s)-1]
s = s[:len(s)-1]
// Stack (use slice)
stack := []int{}
stack = append(stack, val) // push
top := stack[len(stack)-1] // peek
stack = stack[:len(stack)-1] // pop
// Slices are reference types — copy before modifying if needed
original := []int{1, 2, 3}
shallow := original // same underlying array!
deepCopy := append([]int{}, original...) // true copy
Key tip: Slices in Go are reference types — assigning a slice to another variable does not copy the data. Use append([]int{}, s...) or copy for a true deep copy. This trips up many candidates coming from Python or Java.
4. Maps
// Declare and initialize
m := map[string]int{} // empty map
m2 := map[string]int{"alice": 10, "bob": 20}
m3 := make(map[string]int) // same as {}
// Access
m["alice"] // 10
m["missing"] // 0 (zero value — no error!)
// Safe access with existence check
val, ok := m["alice"]
if ok {
fmt.Println(val)
}
// Modify
m["carol"] = 30 // insert / update
delete(m, "bob") // delete key (no error if missing)
// Check existence
_, exists := m["alice"] // exists = true
// Length
len(m)
// Frequency map pattern
freq := map[byte]int{}
for _, ch := range []byte(s) {
freq[ch]++ // zero value of int is 0, so this works!
}
// Iterate (random order — do not rely on insertion order)
for k, v := range m {
fmt.Println(k, v)
}
for k := range m { } // keys only
for _, v := range m { } // values only
// Map of slices (adjacency list)
graph := map[int][]int{}
graph[u] = append(graph[u], v)
// Map as set
seen := map[int]bool{}
seen[x] = true
if seen[x] { } // contains check
// Or use struct{} to save memory
seen2 := map[int]struct{}{}
seen2[x] = struct{}{}
_, inSet := seen2[x]
Key tip: Accessing a missing key in a Go map returns the zero value of the value type — 0 for int, false for bool, nil for slices. This is useful (e.g. freq[ch]++ just works) but can mask bugs if you’re not careful.
5. Structs
// Basic struct
type Point struct {
X, Y int
}
p := Point{X: 1, Y: 2}
p.X // 1
p.Y = 5
// Anonymous struct (useful for heap items, pairs)
item := struct {
val, priority int
}{val: 10, priority: 3}
// Struct with methods
type ListNode struct {
Val int
Next *ListNode
}
// Constructor pattern
func NewListNode(val int) *ListNode {
return &ListNode{Val: val}
}
// Methods
func (n *ListNode) String() string {
return fmt.Sprintf("%d", n.Val)
}
// Tree node
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
// Comparable struct for use as map key
type Coord struct{ Row, Col int }
visited := map[Coord]bool{}
visited[Coord{0, 0}] = true
6. Control Flow
// if / else if / else
if x > 0 {
} else if x == 0 {
} else {
}
// if with short statement (scope limited to if block)
if v, err := strconv.Atoi(s); err == nil {
fmt.Println(v)
}
// for — the only loop in Go
for i := 0; i < n; i++ { }
for i := n - 1; i >= 0; i-- { }
for i := 0; i < n; i += 2 { }
// while equivalent
for condition { }
// infinite loop
for { }
// range loop
for i, v := range slice { }
for k, v := range m { }
for i, r := range str { } // byte index, rune value
// break / continue
for i := 0; i < n; i++ {
if i == 5 { break }
if i%2 == 0 { continue }
}
// Labeled break (nested loops)
outer:
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if grid[i][j] == target {
break outer
}
}
}
// switch (no fallthrough by default)
switch x {
case 1:
fmt.Println("one")
case 2, 3:
fmt.Println("two or three")
default:
fmt.Println("other")
}
// switch with no condition (like if-else chain)
switch {
case x < 0: fmt.Println("negative")
case x == 0: fmt.Println("zero")
default: fmt.Println("positive")
}
7. Functions
// Basic function
func add(a, b int) int {
return a + b
}
// Multiple return values (idiomatic Go)
func minMax(s []int) (int, int) {
min, max := s[0], s[0]
for _, v := range s {
if v < min { min = v }
if v > max { max = v }
}
return min, max
}
lo, hi := minMax(arr)
// Named return values
func divide(a, b float64) (result float64, err error) {
if b == 0 {
err = fmt.Errorf("division by zero")
return
}
result = a / b
return
}
// Variadic functions
func sum(nums ...int) int {
total := 0
for _, n := range nums { total += n }
return total
}
sum(1, 2, 3)
sum(arr...) // spread slice into variadic
// First-class functions
apply := func(f func(int) int, x int) int {
return f(x)
}
apply(func(x int) int { return x * x }, 5) // 25
// Closures
func makeCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
counter := makeCounter()
counter() // 1
counter() // 2
// Recursive function
func fib(n int) int {
if n <= 1 { return n }
return fib(n-1) + fib(n-2)
}
// Pass slice by reference (slices are already references)
func reverse(s []int) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
8. Sorting
import "sort"
s := []int{3, 1, 4, 1, 5}
// Sort ascending
sort.Ints(s) // in-place
// Sort descending
sort.Sort(sort.Reverse(sort.IntSlice(s)))
// sort.Slice — custom comparator (most flexible)
sort.Slice(s, func(i, j int) bool {
return s[i] < s[j] // ascending
})
sort.Slice(s, func(i, j int) bool {
return s[i] > s[j] // descending
})
// Sort strings
words := []string{"banana", "fig", "apple"}
sort.Strings(words) // lexicographic
sort.Slice(words, func(i, j int) bool {
return len(words[i]) < len(words[j]) // by length
})
// Sort 2D slice
pairs := [][]int{{1, 3}, {2, 1}, {3, 2}}
sort.Slice(pairs, func(i, j int) bool {
return pairs[i][1] < pairs[j][1] // by second element
})
// Sort by multiple keys
sort.Slice(pairs, func(i, j int) bool {
if pairs[i][0] != pairs[j][0] {
return pairs[i][0] < pairs[j][0] // by first asc
}
return pairs[i][1] > pairs[j][1] // tie-break by second desc
})
// Sort structs
type Person struct{ Name string; Age int }
people := []Person{{"Bob", 25}, {"Alice", 30}, {"Carol", 25}}
sort.Slice(people, func(i, j int) bool {
if people[i].Age != people[j].Age {
return people[i].Age < people[j].Age
}
return people[i].Name < people[j].Name
})
// Stable sort (preserves relative order of equal elements)
sort.SliceStable(s, func(i, j int) bool {
return s[i] < s[j]
})
// Check if sorted
sort.IntsAreSorted(s)
sort.StringsAreSorted(words)
sort.SliceIsSorted(s, func(i, j int) bool { return s[i] <= s[j] })
9. Binary Search
import "sort"
s := []int{1, 3, 5, 7, 9} // must be sorted
// sort.SearchInts — returns leftmost index where s[i] >= target
idx := sort.SearchInts(s, 5) // 2
idx2 := sort.SearchInts(s, 4) // 2 (insertion point)
// Check if value exists
i := sort.SearchInts(s, 5)
exists := i < len(s) && s[i] == 5
// sort.Search — general binary search (find first i where f(i) is true)
// f must be: false, false, ..., true, true (monotonically non-decreasing)
n := len(s)
i = sort.Search(n, func(i int) bool { return s[i] >= 5 }) // lower bound
i = sort.Search(n, func(i int) bool { return s[i] > 5 }) // upper bound
// Count occurrences
lo := sort.SearchInts(s, target)
hi := sort.Search(len(s), func(i int) bool { return s[i] > target })
count := hi - lo
// Manual binary search template
lo, hi := 0, len(s)-1
for lo <= hi {
mid := lo + (hi-lo)/2 // avoids overflow
if s[mid] == target {
return mid
} else if s[mid] < target {
lo = mid + 1
} else {
hi = mid - 1
}
}
// Binary search on answer (monotonic predicate)
lo, hi = 0, int(1e9)
for lo < hi {
mid := lo + (hi-lo)/2
if feasible(mid) {
hi = mid
} else {
lo = mid + 1
}
}
// lo is the minimum feasible value
10. Stack & Queue
Go has no built-in stack or queue — use slices for both.
// Stack (LIFO) — use slice
stack := []int{}
// Push
stack = append(stack, val)
// Peek
top := stack[len(stack)-1]
// Pop
top = stack[len(stack)-1]
stack = stack[:len(stack)-1]
// Is empty
len(stack) == 0
// Queue (FIFO) — two options:
// Option 1: slice with index pointer (O(1) dequeue, wastes memory)
queue := []int{}
head := 0
queue = append(queue, val) // enqueue
front := queue[head] // peek
head++ // dequeue
// Option 2: slice with re-slicing (simple, GC handles memory)
queue = append(queue, val) // enqueue
front = queue[0] // peek
queue = queue[1:] // dequeue (O(1) view, not copy)
// For interview use, option 2 is cleaner to write
// For performance-critical BFS, use option 1
// BFS queue pattern (most common)
queue := []int{start}
for len(queue) > 0 {
node := queue[0]
queue = queue[1:]
// process node
for _, neighbor := range graph[node] {
queue = append(queue, neighbor)
}
}
11. Heap (Priority Queue)
Go’s container/heap package requires implementing an interface — verbose but powerful.
import "container/heap"
// Min-heap of integers
type MinHeap []int
func (h MinHeap) Len() int { return len(h) }
func (h MinHeap) Less(i, j int) bool { return h[i] < h[j] } // min-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)
x := old[n-1]
*h = old[:n-1]
return x
}
// Usage
h := &MinHeap{3, 1, 4, 1, 5}
heap.Init(h) // O(n) heapify
heap.Push(h, 2) // O(log n)
min := heap.Pop(h).(int) // O(log n)
(*h)[0] // peek min — O(1)
// Max-heap: flip the Less comparison
type MaxHeap []int
func (h MaxHeap) Less(i, j int) bool { return h[i] > h[j] } // max-heap
// Heap of pairs — sort by priority
type Item struct {
val, priority int
}
type PairHeap []Item
func (h PairHeap) Len() int { return len(h) }
func (h PairHeap) Less(i, j int) bool { return h[i].priority < h[j].priority }
func (h PairHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *PairHeap) Push(x any) { *h = append(*h, x.(Item)) }
func (h *PairHeap) Pop() any {
old := *h; n := len(old)
x := old[n-1]; *h = old[:n-1]
return x
}
// K largest elements using min-heap of size k
func kLargest(nums []int, k int) []int {
h := &MinHeap{}
heap.Init(h)
for _, n := range nums {
heap.Push(h, n)
if h.Len() > k {
heap.Pop(h)
}
}
return []int(*h)
}
Key tip: The heap interface boilerplate is verbose — practice writing it from memory before your interview. In a pinch, you can also sort the slice and use it as a pseudo-priority queue if you don’t need dynamic insertions.
12. Sets (via Map)
Go has no built-in set. Use map[T]bool or map[T]struct{}.
// Set using map[T]bool (simpler)
set := map[int]bool{}
set[1] = true
set[2] = true
set[1] // true
delete(set, 1)
len(set) // 1
// Contains check
if set[x] { } // false for missing keys — works!
// Set using map[T]struct{} (zero memory for value)
set2 := map[int]struct{}{}
set2[1] = struct{}{}
_, exists := set2[1] // explicit exists check
// Build set from slice
func toSet(s []int) map[int]bool {
m := make(map[int]bool, len(s))
for _, v := range s { m[v] = true }
return m
}
// Set operations
func intersection(a, b map[int]bool) map[int]bool {
result := map[int]bool{}
for k := range a {
if b[k] { result[k] = true }
}
return result
}
func union(a, b map[int]bool) map[int]bool {
result := map[int]bool{}
for k := range a { result[k] = true }
for k := range b { result[k] = true }
return result
}
func difference(a, b map[int]bool) map[int]bool {
result := map[int]bool{}
for k := range a {
if !b[k] { result[k] = true }
}
return result
}
13. Math & Numbers
import "math"
// Math functions
math.Max(float64(a), float64(b)) // requires float64!
math.Min(float64(a), float64(b))
math.Abs(float64(x))
math.Sqrt(float64(x))
math.Pow(2, 10) // 1024.0
math.Floor(3.7) // 3.0
math.Ceil(3.2) // 4.0
math.Log(x) // natural log
math.Log2(x)
math.Log10(x)
// Integer max/min (no built-in for int — write helpers)
func maxInt(a, b int) int {
if a > b { return a }
return b
}
func minInt(a, b int) int {
if a < b { return a }
return b
}
func absInt(x int) int {
if x < 0 { return -x }
return x
}
// Go 1.21+ has built-in min/max for ordered types
// min(a, b)
// max(a, b)
// Integer limits
math.MaxInt // largest int
math.MinInt // smallest int
math.MaxInt32
math.MinInt32
math.MaxInt64
math.MinInt64
// GCD
func gcd(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
// LCM
func lcm(a, b int) int {
return a / gcd(a, b) * b // divide first to avoid overflow
}
// Modular arithmetic
result := ((a % MOD) * (b % MOD)) % MOD
result = ((result + MOD) % MOD) // ensure positive
// Fast modular exponentiation
func powmod(base, exp, mod int) int {
result := 1
base %= mod
for exp > 0 {
if exp&1 == 1 {
result = result * base % mod
}
base = base * base % mod
exp >>= 1
}
return result
}
// Integer square root
func isqrt(n int) int {
return int(math.Sqrt(float64(n)))
}
Key tip: Go’s math.Max and math.Min only work on float64. For int comparisons you need to write a helper or use an if expression inline. Go 1.21 added built-in min and max for ordered types — worth knowing if your interviewer allows a recent Go version.
14. Bit Manipulation
// Bitwise operators
x & y // AND
x | y // OR
x ^ y // XOR
^x // NOT (bitwise complement) — note: ^ not ~
x << k // left shift
x >> k // right shift (arithmetic for signed int)
// Useful tricks
x & 1 // check if x is odd
x & (x - 1) // clear lowest set bit
x & (-x) // isolate lowest set bit
x ^ x // 0
x ^ 0 // x
// Power of 2 check
func isPow2(x int) bool {
return x > 0 && x&(x-1) == 0
}
// Count set bits (no built-in)
func popcount(x int) int {
count := 0
for x != 0 {
x &= x - 1
count++
}
return count
}
// Or use math/bits package
import "math/bits"
bits.OnesCount(uint(x)) // count set bits
bits.Len(uint(x)) // bits needed to represent x
bits.TrailingZeros(uint(x)) // count trailing zeros
bits.LeadingZeros(uint(x)) // count leading zeros
// Set / clear / toggle / read bit k
x |= 1 << k // set bit k
x &^= 1 << k // clear bit k (&^ is Go's AND NOT)
x ^= 1 << k // toggle bit k
(x >> k) & 1 // read bit k
// Iterate all subsets of n elements
for mask := 0; mask < 1<<n; mask++ {
for i := 0; i < n; i++ {
if mask>>i&1 == 1 {
// element i is in this subset
}
}
}
Key tip: Go uses ^ for both XOR (binary operator) and bitwise NOT (unary operator). Also, Go’s “AND NOT” is &^ — used to clear bits: x &^= mask clears all bits set in mask. This trips up candidates who expect ~ from C/C++/Java.
15. Common Algorithm Patterns
These are the templates that cover the vast majority of Go coding interview questions. The patterns are the same as other languages — Go’s syntax just requires a few more lines.
Two Pointers
func twoSumSorted(arr []int, target int) (int, int) {
l, r := 0, len(arr)-1
for l < r {
sum := arr[l] + arr[r]
if sum == target {
return l, r
} else if sum < target {
l++
} else {
r--
}
}
return -1, -1
}
Sliding Window
func maxSumSubarray(arr []int, k int) int {
window := 0
for i := 0; i < k; i++ {
window += arr[i]
}
best := window
for i := k; i < len(arr); i++ {
window += arr[i] - arr[i-k]
if window > best {
best = window
}
}
return best
}
Fast & Slow Pointers
func hasCycle(head *ListNode) bool {
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
if slow == fast {
return true
}
}
return false
}
BFS Template
func bfs(graph map[int][]int, start int) {
visited := map[int]bool{start: true}
queue := []int{start}
for len(queue) > 0 {
node := queue[0]
queue = queue[1:]
for _, neighbor := range graph[node] {
if !visited[neighbor] {
visited[neighbor] = true
queue = append(queue, neighbor)
}
}
}
}
DFS Template (Recursive)
func dfs(graph map[int][]int, node int, visited map[int]bool) {
visited[node] = true
for _, neighbor := range graph[node] {
if !visited[neighbor] {
dfs(graph, neighbor, visited)
}
}
}
DFS Template (Iterative)
func dfsIterative(graph map[int][]int, start int) {
visited := map[int]bool{}
stack := []int{start}
for len(stack) > 0 {
node := stack[len(stack)-1]
stack = stack[:len(stack)-1]
if visited[node] {
continue
}
visited[node] = true
for _, neighbor := range graph[node] {
stack = append(stack, neighbor)
}
}
}
Binary Search on Answer
lo, hi := 0, int(1e9)
for lo < hi {
mid := lo + (hi-lo)/2
if feasible(mid) {
hi = mid
} else {
lo = mid + 1
}
}
// lo is the minimum feasible value
Dynamic Programming — Memoization
func solve(n int, memo map[int]int) int {
if n <= 1 { return n }
if v, ok := memo[n]; ok { return v }
result := solve(n-1, memo) + solve(n-2, memo)
memo[n] = result
return result
}
// Call with: solve(n, map[int]int{})
// With a slice for dense integer states
var dp func(i int) int
cache := make([]int, n+1)
for i := range cache { cache[i] = -1 }
dp = func(i int) int {
if i <= 1 { return i }
if cache[i] != -1 { return cache[i] }
cache[i] = dp(i-1) + dp(i-2)
return cache[i]
}
Prefix Sum
func buildPrefix(arr []int) []int {
prefix := make([]int, len(arr)+1)
for i, v := range arr {
prefix[i+1] = prefix[i] + v
}
return prefix
}
// Range sum [l, r] inclusive: prefix[r+1] - prefix[l]
Monotonic Stack
func nextGreater(arr []int) []int {
n := len(arr)
result := make([]int, n)
for i := range result { result[i] = -1 }
stack := []int{} // stores indices
for i := 0; i < n; i++ {
for len(stack) > 0 && arr[i] > arr[stack[len(stack)-1]] {
top := stack[len(stack)-1]
stack = stack[:len(stack)-1]
result[top] = arr[i]
}
stack = append(stack, i)
}
return result
}
Union-Find
type UnionFind struct {
parent []int
rank []int
}
func NewUnionFind(n int) *UnionFind {
parent := make([]int, n)
rank := make([]int, n)
for i := range parent { parent[i] = i }
return &UnionFind{parent, rank}
}
func (uf *UnionFind) Find(x int) int {
if uf.parent[x] != x {
uf.parent[x] = uf.Find(uf.parent[x]) // path compression
}
return uf.parent[x]
}
func (uf *UnionFind) Unite(x, y int) bool {
px, py := uf.Find(x), uf.Find(y)
if px == py { return false }
if uf.rank[px] < uf.rank[py] { px, py = py, px }
uf.parent[py] = px
if uf.rank[px] == uf.rank[py] { uf.rank[px]++ }
return true
}
func (uf *UnionFind) Connected(x, y int) bool {
return uf.Find(x) == uf.Find(y)
}
Quick Reference Cheat Sheet
| Task | Snippet |
|---|---|
| Declare slice | s := []int{1, 2, 3} |
| Make slice | make([]int, n) |
| Append | s = append(s, val) |
| Copy slice | append([]int{}, s...) |
| Last element | s[len(s)-1] |
| Pop (stack) | s = s[:len(s)-1] |
| Reverse slice | for i,j:=0,len(s)-1; i<j; i,j=i+1,j-1 { s[i],s[j]=s[j],s[i] } |
| Sort ascending | sort.Ints(s) |
| Sort custom | sort.Slice(s, func(i,j int) bool { return s[i] < s[j] }) |
| Binary search | sort.SearchInts(s, val) |
| Map default | m[key] returns zero value — m[k]++ works |
| Map exists | v, ok := m[k] |
| Set | map[int]bool{} |
| String builder | var sb strings.Builder; sb.WriteString(...) |
| String → int | strconv.Atoi(s) |
| Int → string | strconv.Itoa(n) |
| Rune iteration | for i, r := range s { } |
| Bit NOT | ^x (not ~x) |
| Clear bit k | x &^= 1 << k |
| Count set bits | bits.OnesCount(uint(x)) |
| Max int | math.MaxInt |
| GCD | for b!=0 { a,b=b,a%b }; return a |
Go-Specific Interview Gotchas
These are the traps that catch candidates who know Go casually but haven’t coded it under pressure:
| Gotcha | Wrong | Right |
|---|---|---|
| Bitwise NOT | ~x | ^x |
| Clear bit | x &= ~(1<<k) | x &^= 1 << k |
| Slice copy | b := a (same backing array) | b := append([]int{}, a...) |
| math.Max on int | math.Max(a, b) | write maxInt helper (or use Go 1.21 max) |
| String length | len(s) (bytes) | len([]rune(s)) (chars) |
| Map nil panic | var m map[int]int; m[1]=1 | m := map[int]int{} |
| Heap pop type | heap.Pop(h) | heap.Pop(h).(int) (type assert) |
| No built-in set | set := []int{} | set := map[int]bool{} |
Related Interview Topics
Comfortable with Go fundamentals? The next step is applying these tools to the core problem categories:
- Arrays & Hashing —
map[int]intfrequency maps,map[int]boolsets, sliding window - Binary Search —
sort.Search,sort.SearchInts, binary search on answer - Trees & Graphs — BFS with slice queue, recursive DFS, topological sort
- Dynamic Programming — memoization with
map[int]int, tabulation with[]int - Heaps & Greedy —
container/heapinterface, k-th largest, Dijkstra
Each of these patterns has dedicated walkthroughs on the Intervu blog.
Practice Under Real Interview Conditions
Go’s simplicity is a genuine strength in interviews — but only if you’re fluent enough that the syntax doesn’t slow you down. Forgetting the heap interface, blanking on sort.Slice’s comparator signature, or spending two minutes on a minInt helper can cost you under a real time limit.
The best way to build that fluency is repetition under pressure. Intervu gives you AI-powered mock coding interviews that simulate exactly that — timed, with follow-up questions, and instant feedback on your approach and your code.
Ready to put it to the test? Start a free mock interview on Intervu →