Skip to content
Skilled.dev

Language preparation

Go coding interview preparation: slices, maps, and text

Practice Go slice ownership, map presence checks, byte and rune boundaries, and queue-based graph traversal with worked code.

Published · 5 min read

Go interview code depends on a few distinctions that compact syntax can hide: a slice and its backing array, an absent map key and a stored zero, a byte offset and a rune, a copied slice header and copied elements. Prepare those distinctions while practicing the collection operations your algorithm needs.

The examples use standard Go without a dependency or a generic helper library. The integer-pair function deliberately uses an explicit int64 value model. The lesson editor may provide a different signature, so adapt the types and return shape to the published exercise contract.

Separate slice length, capacity, and ownership

A slice describes a window into a backing array. Assigning a slice to another variable copies that description, so both slices can still refer to the same elements. Mutating an overlapping element through one view can be visible through the other.

Appending may reuse available capacity or allocate new storage. A program that appears independent after one append can behave differently when spare capacity changes. Choose whether shared backing storage is allowed instead of using allocation behavior as an accidental ownership rule. The Go slices article explains the representation and copying behavior.

When saving a backtracking result, allocate a new slice and copy the path into it. For an empty result, decide whether a nil slice and an allocated empty slice are equivalent in your output contract. Their lengths match, but an external serializer can represent them differently. A copied slice of pointers still refers to the same pointed-to objects.

Use the map presence result

A lookup in map[int64]int returns an integer's zero value when the key is missing. Index zero is also a valid stored index, so checking that value alone loses information. Go's two-result lookup supplies the missing presence bit.

package main

func twoSum(values []int64, target int64) ([2]int, bool) {
    previous := make(map[int64]int)
    for index, value := range values {
        if earlier, exists := previous[target-value]; exists {
            return [2]int{earlier, index}, true
        }
        previous[value] = index
    }
    return [2]int{}, false
}

func bfsOrder(graph map[string][]string, start string) []string {
    queue := []string{start}
    seen := map[string]bool{start: true}
    order := make([]string, 0)
    for head := 0; head < len(queue); head++ {
        node := queue[head]
        order = append(order, node)
        for _, neighbor := range graph[node] {
            if !seen[neighbor] {
                seen[neighbor] = true
                queue = append(queue, neighbor)
            }
        }
    }
    return order
}

For this Two Sum implementation, values and target are guaranteed to lie between negative one billion and positive one billion. Their differences fit int64. The function does not validate that precondition, and it should not be advertised as overflow-safe for unrestricted int64 inputs. A successful result contains distinct indexes because lookup precedes insertion. When the bool is false, the zero-filled pair is not an answer.

A nil map supports reads but cannot receive an assignment. make creates a writable map for earlier indexes. Map iteration order is unspecified; this function traverses the input slice instead, so result discovery follows input order. Expected linear hash-map work is the standard algorithmic model, not a language promise that every map operation has a strict worst-case constant bound.

Explain the queue's retained storage

The BFS uses a slice with a moving head index. Appending adds new work, and advancing head consumes the next queued value. Marking a neighbor before appending prevents repeated queue entries in cyclic or converging graphs. A missing adjacency key behaves as an empty neighbor slice.

This short-lived queue retains all appended labels until the function returns, including consumed entries. That is O(V) queue storage over the reachable vertices, alongside the visited map and returned order. It is appropriate for this bounded traversal, but a long-lived queue may need to clear consumed reference values, compact, or use a circular buffer to avoid retaining old objects indefinitely.

For a graph with integer labels, the same invariant can use an integer slice and a membership set represented by map[int]struct{}. The set representation communicates that only key presence matters. A bool map can also model membership when your convention never stores false as a meaningful visited entry.

Distinguish bytes, runes, and displayed characters

A Go string contains bytes. Its length is a byte length, and indexing returns a byte. Ranging over a valid UTF-8 string decodes runes, with the loop index identifying a byte offset rather than a consecutive rune position.

For "a🙂b", the rune-start byte offsets are zero, one, and five. Converting to []rune gives three indexed code points and allocates storage for them. If a substring must be returned using original byte boundaries, track the offsets instead of treating a rune count as a byte index.

Runes are still code points, which can combine into a single user-perceived grapheme cluster. An exercise restricted to ASCII avoids those extra segmentation questions. General text needs an explicit character model, as well as a policy for invalid UTF-8 if the input may contain arbitrary bytes. The Go language specification defines string range behavior, including its indexes.

Use heap interfaces and numeric types deliberately

The standard container/heap package operates on a collection implementing its interface, including length, ordering, swapping, and pointer-receiver push/pop methods. The collection's Pop method removes the final backing-slice element; the package's heap operation performs the priority rearrangement first. Confusing those two layers can return the wrong item.

Read the heap package contract before implementing a priority queue from memory. Choose whether smaller or larger values compare first and test duplicate priorities. A queue for BFS does not need this ordering machinery because every edge represents the same one-hop step.

Use int for ordinary slice indexes. Choose a value type from the problem's numeric bounds, rather than assuming int has the same width in every environment. Integer wraparound does not make a mathematically overflowing answer correct. If the result can exceed the chosen type, widen operands before arithmetic where a wider type exists, check operations, or choose a larger-number representation.

Test data sharing as well as output values

For Two Sum, include an index-zero answer, duplicate values, one value, no match, negative values, and the stated numeric boundaries. Validate the pair's positions and sum instead of requiring a particular valid pair. For BFS, include a cycle, a shared neighbor, a neighbor-only node, and an absent start key.

For a copied path, modify the original after saving and verify the saved result remains unchanged. Repeat with slices that have spare capacity so your test does not depend on append allocating. For text, test ASCII and a supplementary code point and state whether your output counts bytes or runes.

Work through Two Sum, BFS, and linked-list reversal. Use the backtracking guide to practice restoration and result copying, then explain the memory retained by the Go values you actually used.

Worked lesson walkthroughs

58 reading lessons with code examples in this language.

Concepts

Concept lesson

Arrays in Go

Learn array insertion in Go. Trace a copied result, explain shifting costs, and check empty inputs and endpoint positions without changing the original.

Concept lesson

Big O time and space complexity in Go

Analyze time and space complexity in Go with a suffix-copy example. Count nested work, returned storage, and allocation instead of counting loops alone.

Concept lesson

Hash Tables in Go

Count frequencies with a hash map in Go. Preserve input order, distinguish missing keys from zero, and explain expected lookup time and retained storage.

Concept lesson

Strings in Go

Practice string construction in Go with a repeat-text example. Explain builders, copies, Unicode representation, output size, and boundary cases.

Concept lesson

Palindromes, permutations, and anagrams in Go

Check an ASCII-normalized palindrome in Go. Trace two-pointer comparisons, case handling, ignored characters, and the limits of the text contract.

Concept lesson

Recursion in Go

Trace recursive factorial in Go from the base case through returning calls. Explain termination, stack space, integer limits, and boundary tests.

Concept lesson

Logarithmic time in Go: repeated halving and search

Understand logarithmic loops in Go by counting integer halvings. Test powers of two, explain rounding, and derive the exact step count.

Concept lesson

Binary search in Go: invariants and boundary tests

Write first-occurrence binary search in Go. Trace half-open bounds, duplicate values, missing targets, and the random-access assumption behind O(log n).

Concept lesson

Sorting in Go

Return a numerically sorted copy in Go. Preserve duplicates and the original input, choose the right library operation, and account for copied storage.

Concept lesson

Linked Lists in Go

Find a linked list's middle in Go with slow and fast runners. Define the even-length result, handle an empty list, and separate construction from traversal.

Concept lesson

Pointers in Go

Trace shared mutation and reference rebinding in Go. Follow two aliases through one object update and a new allocation, with explicit ownership notes.

Concept lesson

Queues in Go

Practice FIFO queue behavior in Go. Compare efficient front removal with a head cursor, preserve repeated values, and count fill-and-drain costs.

Concept lesson

Stacks in Go

Practice LIFO stack behavior in Go. Trace push and pop, separate empty state from zero payloads, and explain node ownership and end-operation costs.

Concept lesson

Trees in Go

Compute binary-tree edge height in Go. Read heap-indexed nullable slots, handle an empty root, and account for reachable nodes and recursion depth.

Concept lesson

Tree traversal in Go: in-order, pre-order, and post-order

Trace in-order binary-tree traversal in Go. Explain nullable child positions, visit order, recursion space, and when the output is actually sorted.

Concept lesson

Binary Search Trees in Go

Search a binary search tree in Go. Follow one ordered path, handle absent children, and relate search cost to height without assuming balance.

Concept lesson

Graphs in Go

Read graph adjacency lists in Go and compute out-degrees. Define vertex IDs, parallel edges, self-loops, representation costs, and input assumptions.

Concept lesson

Depth-First Search in Go

Implement iterative DFS in Go. Preserve listed neighbor order, skip repeated visits, trace a shared descendant, and explain pending-stack costs.

Concept lesson

Breadth-First Search in Go

Implement BFS in Go with FIFO order and enqueue-time discovery. Trace graph layers, cycles, shared descendants, and visited-storage costs.

Concept lesson

Subproblems and Overlapping Subproblems in Go

Count naive Fibonacci calls in Go. Trace overlapping states, include base-case work, and identify the cache key before applying memoization.

Concept lesson

Memoization in Go

Memoize Fibonacci in Go and count distinct computed states. Preserve cached zero, define cache lifetime, and explain remaining recursion depth.

Concept lesson

Bottom-Up vs. Top-Down in Go

Build a bottom-up Fibonacci table in Go. Follow dependency order, test zero input, and compare full-table storage with rolling-state alternatives.

Concept lesson

Dynamic Programming in Go

Solve minimum coin count in Go. Trace the recurrence, represent unreachable states, test a greedy counterexample, and explain amount-based table costs.

Data structure implementations

Implementation tutorial

Implement a dynamic array in Go

Implement a map-backed teaching array in Go. Trace push, pop, insertion, and removal, including logical length, missing indices, and obsolete entries.

Implementation tutorial

Implement a hash table in Go: collisions, updates, and removal

Build a hash table in Go with separate chaining. Follow colliding keys through lookup, update, and deletion, and explain the limits of a fixed teaching hash.

Implementation tutorial

Implement a linked list in Go: head, tail, and node identity

Build a doubly linked list in Go. Trace prepend and append, verify reciprocal links and both endpoints, and explain ownership and retention.

Implementation tutorial

Implement a queue in Go: FIFO links and empty transitions

Implement a linked queue in Go. Trace FIFO order, the last removal, and refilling an empty queue while preserving first and last endpoint invariants.

Implementation tutorial

Implement a stack in Go: push, pop, and ownership

Implement a linked stack in Go. Follow the top link through push, peek, and pop, including empty state, returned nodes, and retained chains.

Implementation tutorial

Implement a binary search tree in Go: insert and search

Build a binary search tree in Go. Trace insertion and search, preserve duplicate keys on the right, and test skewed shapes without assuming balancing.

Implementation tutorial

Implement a graph in Go: adjacency lists and edge removal

Build an adjacency-list graph in Go. Trace directed and undirected edges, self-loops, parallel entries, and removal of incoming and outgoing edges.

Practice problems

Practice walkthrough

Two Sum in Go: all index pairs with checked integer arithmetic

Find every matching index pair in Go with map comma-ok lookups. Guard int subtraction overflow and preserve the original slice and indexes.

Practice walkthrough

Valid brackets in Go: ASCII delimiters and UTF-8 text

Validate nested brackets in Go using an explicit rune stack. Distinguish byte offsets from runes, ignore other text, and test Unicode and nesting.

Practice walkthrough

Product of array except self in Go: int64 slices and two directional passes

Build product of array except self in Go with an int64 result slice. Explain make, append versus indexing, slice aliasing, and numeric bounds.

Practice walkthrough

Counting sort for ages in Go: worked solution

Sort bounded ages with a frequency table, preserving duplicate values. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Best stock profit in Go: one transaction

Find the best single chronological stock trade with one scan. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Most frequent email in Go: hash-map solution

Count email occurrences and return the unique most frequent address. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

First Bad Version in Go: boundary binary search

Find the first true value in a monotone version predicate. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Reverse a linked list in Go: pointer walkthrough

Reverse a linked list by moving nodes from an untouched suffix to a reversed prefix. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Remove kth node from end in Go: zero-based deletion

Delete the zero-based kth node from the end of a linked list. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Merge sorted linked lists in Go: Combine Blockchains

Merge two sorted linked chains while preserving duplicate timestamps. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Count Islands in Go: DFS flood-fill walkthrough

Count side-connected land components with a destructive flood fill of the working grid. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Validate a binary search tree in Go: inherited bounds

Validate every binary-tree node against bounds inherited from all its ancestors. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Binary tree maximum depth in Go: count edges

Measure a binary tree’s longest root-to-leaf path in edges. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Lowest common ancestor in Go: return the original node

Find the lowest common ancestor in a general binary tree and return the original node. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Generate string permutations in Go: positional results

Generate positional string permutations, retaining repeated results for repeated characters. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Group palindrome permutations in Go: counts and keys

Filter palindrome permutations, then group retained strings by character multiset. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Merge intervals in Go: Interview Scheduler

Merge sorted interval coverage with an explicit touching-endpoint rule. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Min-max stack in Go: constant-time extrema

Support stack extrema through histories that retain duplicate record values. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

BFS shortest path in Go: Pilot a Rocket

Find an unweighted shortest route and reconstruct it from predecessor links. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Maze reachability in Go: memoized down/right search

Memoize directed maze reachability while keeping unknown distinct from false. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Search a rotated sorted array in Go: Shifted Search

Search a distinct rotated sorted array by identifying an ordered half. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Search a sorted matrix in Go: staircase walkthrough

Eliminate a row or column at each step in a row-and-column sorted matrix. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

House Robber in Go: maximum nonadjacent sum

Maximize a nonadjacent selection with two rolling prefix optima. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Sum decimal digits in Go: recursive solution

Sum decimal digits through a decreasing recursive integer decomposition. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Count 1, 2, or 3-step paths in Go: Three Moves

Count ordered one-, two-, and three-step routes with rolling dynamic programming. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Coin change in Go: minimum-coin dynamic programming

Minimize unlimited coin usage with a bottom-up amount table. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Validate Sudoku in Go: rows, columns, and subsquares

Validate filled Sudoku entries against rows, columns, and subsquares. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Spiral matrix traversal in Go: Walk a Matrix

Traverse a rectangle in clockwise spiral order using shrinking boundaries. Follow the Go implementation, its correctness argument, worked example, complexity, and boundary tests.