Skip to content

LeetCode in Go: Patterns and Templates

This page is the working notebook for Go-first LeetCode practice.

flowchart LR
A[Variables] --> B[Control Flow]
B --> C[Functions]
C --> D[Collections]
D --> E[Sort / String / Convert]
E --> F[Solve Problem]
var a int = 10
var b int64 = 20
var c float64 = 3.14
var d bool = true
var e string = "go"
var f byte = 'A' // alias for uint8
var g rune = '' // alias for int32 (unicode code point)

Short declaration (most common in solutions):

x := 42
name := "leet"
ok := false

Useful composites:

arr := [3]int{1, 2, 3} // fixed-size array
nums := []int{1, 2, 3} // slice (dynamic)
freq := map[int]int{} // map
seen := make(map[string]bool) // map with make
flowchart TD
A[Choose loop style] --> B{Known iteration count?}
B -- Yes --> C[Classic for i := 0; i < n; i++]
B -- No --> D{Condition-based?}
D -- Yes --> E[for condition]
D -- No --> F[for range collection]

Classic for:

for i := 0; i < n; i++ {
// use i
}

while style:

for left < right {
left++
}

Infinite loop:

for {
break
}

Range over slice:

for i, v := range nums {
_ = i
_ = v
}

Range over map:

for k, v := range freq {
_ = k
_ = v
}
if x > 0 {
// ...
} else if x == 0 {
// ...
} else {
// ...
}
switch x {
case 1, 2:
// ...
default:
// ...
}
func add(a, b int) int {
return a + b
}
func setZero(nums []int) { // slices are descriptor values; underlying array can change
if len(nums) > 0 {
nums[0] = 0
}
}
func grow(mp map[int]int) { // maps are reference-like
mp[1]++
}
n := len(nums)
nums = append(nums, 4)
copy(dst, src)
delete(freq, key)
import "sort"
sort.Ints(nums)
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][0] < intervals[j][0]
})
import "strconv"
s := "123"
v, _ := strconv.Atoi(s)
str := strconv.Itoa(v)
for i, ch := range s { // ch is rune
_ = i
_ = ch
}
  1. Prefer slices over arrays for inputs.
  2. Preallocate when size is known: make([]int, 0, n).
  3. Use map[value]index for lookup problems.
  4. Keep helper functions small and typed explicitly.
  5. Return nil for “not found” slice answers when accepted.
graph LR
A[push 1] --> B[push 2]
B --> C[push 3]
C --> D[pop -> 3]
D --> E[pop -> 2]

Go:

stack := []int{}
// push
stack = append(stack, 10)
// pop
top := stack[len(stack)-1]
stack = stack[:len(stack)-1]
_ = top
// peek
peek := stack[len(stack)-1]
_ = peek

Python:

stack = []
# push
stack.append(10)
# pop
top = stack.pop()
# peek
peek = stack[-1]
graph LR
A[enqueue 1] --> B[enqueue 2]
B --> C[enqueue 3]
C --> D[dequeue -> 1]
D --> E[dequeue -> 2]

Go:

q := []int{}
// enqueue
q = append(q, 1)
// dequeue
front := q[0]
q = q[1:]
_ = front

Python:

from collections import deque
q = deque()
q.append(1) # enqueue
front = q.popleft() # dequeue
graph LR
A[pushFront 2] --> B[2]
B --> C[pushBack 3]
C --> D[2 then 3]
D --> E[popFront -> 2]
E --> F[popBack -> 3]

Go (simple slice approach):

dq := []int{}
// push back
dq = append(dq, 3)
// push front
dq = append([]int{2}, dq...)
// pop front
front := dq[0]
dq = dq[1:]
_ = front
// pop back
back := dq[len(dq)-1]
dq = dq[:len(dq)-1]
_ = back

Python:

from collections import deque
dq = deque()
dq.append(3) # push back
dq.appendleft(2) # push front
front = dq.popleft()
back = dq.pop()
flowchart TD
A[Push values] --> B[Heap property maintained]
B --> C[Pop returns smallest]
C --> D[Repeat for k-smallest / Dijkstra / scheduling]

Go (min-heap):

import "container/heap"
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x any) { *h = append(*h, x.(int)) }
func (h *IntHeap) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
return x
}
h := &IntHeap{}
heap.Init(h)
heap.Push(h, 5)
heap.Push(h, 1)
min := heap.Pop(h).(int)
_ = min

Python (min-heap):

import heapq
h = []
heapq.heappush(h, 5)
heapq.heappush(h, 1)
mn = heapq.heappop(h)
flowchart LR
A[Read element x] --> B{map has x?}
B -- Yes --> C[update count/index]
B -- No --> D[insert x]

Go:

freq := map[int]int{}
for _, n := range nums {
freq[n]++
}

Python:

freq = {}
for n in nums:
freq[n] = freq.get(n, 0) + 1
flowchart LR
A[Value v] --> B{v in set?}
B -- Yes --> C[skip / found duplicate]
B -- No --> D[add v]

Go:

seen := map[int]struct{}{}
seen[5] = struct{}{}
_, ok := seen[5]
delete(seen, 5)
_ = ok

Python:

seen = set()
seen.add(5)
ok = 5 in seen
seen.remove(5)

Go:

type ListNode struct {
Val int
Next *ListNode
}

Python:

class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
graph TD
A[root] --> B[left]
A --> C[right]
B --> D[left.left]
B --> E[left.right]

Go:

type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func dfs(root *TreeNode) {
if root == nil {
return
}
dfs(root.Left)
dfs(root.Right)
}

Python:

class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def dfs(root):
if not root:
return
dfs(root.left)
dfs(root.right)
flowchart TD
A[Init queue with root] --> B[Pop front]
B --> C[Process node]
C --> D[Push children]
D --> E{Queue empty?}
E -- No --> B
E -- Yes --> F[Done]

Go:

func bfs(root *TreeNode) {
if root == nil {
return
}
q := []*TreeNode{root}
for len(q) > 0 {
node := q[0]
q = q[1:]
_ = node
if node.Left != nil {
q = append(q, node.Left)
}
if node.Right != nil {
q = append(q, node.Right)
}
}
}

Python:

from collections import deque
def bfs(root):
if not root:
return
q = deque([root])
while q:
node = q.popleft()
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
flowchart LR
A[Input time string / now] --> B[Parse or get current]
B --> C[Normalize timezone]
C --> D[Compute duration / compare]
D --> E[Format output]

Go:

import "time"
now := time.Now()
utc := now.UTC()

Python:

from datetime import datetime, timezone
now = datetime.now()
utc_now = datetime.now(timezone.utc)

Go:

tsSec := time.Now().Unix() // seconds
tsMilli := time.Now().UnixMilli()
t := time.Unix(tsSec, 0)

Python:

from datetime import datetime
ts_sec = int(datetime.now().timestamp())
t = datetime.fromtimestamp(ts_sec)

Go (time uses reference layout 2006-01-02 15:04:05):

import "time"
s := "2026-02-22T05:00:00Z"
t, err := time.Parse(time.RFC3339, s)
if err != nil {
// handle error
}
out := t.Format("2006-01-02 15:04:05")
_ = out

Python:

from datetime import datetime
s = "2026-02-22T05:00:00+00:00"
t = datetime.fromisoformat(s)
out = t.strftime("%Y-%m-%d %H:%M:%S")

Go:

import "time"
loc, err := time.LoadLocation("America/Chicago")
if err != nil {
// handle error
}
local := time.Now().In(loc)
_ = local

Python:

from datetime import datetime
from zoneinfo import ZoneInfo
local = datetime.now(ZoneInfo("America/Chicago"))

Go:

import "time"
start := time.Now()
deadline := start.Add(30 * time.Minute)
elapsed := time.Since(start)
diff := deadline.Sub(start)
_ = elapsed
_ = diff

Python:

from datetime import datetime, timedelta
start = datetime.now()
deadline = start + timedelta(minutes=30)
elapsed = datetime.now() - start
diff = deadline - start

When a problem is about intervals/scheduling, convert times to int minutes or seconds early and work with integers for simpler comparisons and sorting.

flowchart LR
A[Open/read file] --> B[Transform data]
B --> C[Write/append result]
C --> D[Close/flush]

Go:

import "os"
data, err := os.ReadFile("input.txt")
if err != nil {
// handle error
}
text := string(data)
_ = text

Python:

with open("input.txt", "r", encoding="utf-8") as f:
text = f.read()

Go:

import "os"
err := os.WriteFile("output.txt", []byte("hello\n"), 0o644)
if err != nil {
// handle error
}

Python:

with open("output.txt", "w", encoding="utf-8") as f:
f.write("hello\n")

Go:

import "os"
f, err := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
// handle error
}
defer f.Close()
_, err = f.WriteString("new line\n")
if err != nil {
// handle error
}

Python:

with open("log.txt", "a", encoding="utf-8") as f:
f.write("new line\n")

Go:

import (
"bufio"
"os"
)
f, err := os.Open("input.txt")
if err != nil {
// handle error
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
_ = line
}
if err := scanner.Err(); err != nil {
// handle error
}

Python:

with open("input.txt", "r", encoding="utf-8") as f:
for line in f:
line = line.rstrip("\n")
flowchart TD
A[Read input] --> B[Call solve function]
B --> C[Apply pattern]
C --> D[Return answer]
D --> E[Print output]
package main
import "fmt"
func solve(nums []int) int {
// TODO
return 0
}
func main() {
fmt.Println(solve([]int{1, 2, 3}))
}
  1. Arrays and Hash Maps
  2. Two Pointers
  3. Sliding Window
  4. Binary Search
  5. Stack / Monotonic Stack
  6. BFS / DFS
  7. Backtracking
  8. Dynamic Programming
  9. Graph Shortest Paths
  10. Heaps / Priority Queues
freq := make(map[int]int)
for _, n := range nums {
freq[n]++
}
q := []int{start}
for len(q) > 0 {
cur := q[0]
q = q[1:]
_ = cur
}
import "container/heap"
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x any) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
return x
}
// usage:
h := &IntHeap{}
heap.Init(h)
heap.Push(h, 3)
heap.Push(h, 1)
min := heap.Pop(h).(int)
_ = min
  1. Two Sum (hash map)
  2. Valid Parentheses (stack)
  3. Binary Search (iterative)
  4. Maximum Subarray (Kadane)
  5. Number of Islands (DFS/BFS)