Skip to content
Skilled.dev

Language preparation

C++ coding interview preparation: STL, ownership, and boundaries

Use vectors, hash maps, queues, and priority queues while handling iterator invalidation, integer overflow, and safe index boundaries.

Published · 5 min read

C++ gives interview solutions direct control over value storage, references, and collection operations. That control also makes lifetime and boundary mistakes part of the algorithm review. Prepare a small standard-library toolkit and explain what remains valid when a container grows or an index changes.

The examples use C++17 features, including std::optional, and standard headers rather than a compiler-specific umbrella header. The course editor's starter signature remains the contract for its exercise. Confirm the configured compiler standard before using features introduced later.

Use vectors without keeping stale references

A std::vector stores its elements contiguously and supports indexed access. Appending may grow its allocation. A reallocation invalidates references, pointers, and iterators into the previous storage, so code that saves auto& current = values[i] and then appends must not assume current remains usable.

reserve requests capacity without creating elements. A vector with capacity ten and size zero still has no valid element at index zero. Use resize when you need initialized elements to index, or append actual values. The vector capacity specification distinguishes size from capacity and describes reallocation invalidation.

For backtracking, results.push_back(path) copies a vector value and preserves that saved path independently. A result containing pointers into a mutable path has a different lifetime contract. For a function that only reads an input vector, a const reference communicates that it need not copy the entire input.

Keep boundary arithmetic in one index model

A half-open binary search uses an upper boundary equal to the length. It never needs to compute length minus one on an empty vector, and every branch makes progress. Indexes use std::size_t consistently.

The map-based Two Sum example uses a wider arithmetic type for a complement computed from int values. It returns an optional pair of indexes, so no-match is separate from a successful pair containing index zero.

#include <cstddef>
#include <optional>
#include <unordered_map>
#include <utility>
#include <vector>

std::size_t lowerBound(const std::vector<int>& values, int target) {
    std::size_t lo = 0;
    std::size_t hi = values.size();
    while (lo < hi) {
        const std::size_t mid = lo + (hi - lo) / 2;
        if (values[mid] >= target) hi = mid;
        else lo = mid + 1;
    }
    return lo;
}

std::optional<std::pair<std::size_t, std::size_t>> twoSum(
    const std::vector<int>& values, int target) {
    std::unordered_map<long long, std::size_t> previous;
    for (std::size_t index = 0; index < values.size(); ++index) {
        const long long complement = static_cast<long long>(target) - values[index];
        const auto found = previous.find(complement);
        if (found != previous.end()) return std::make_pair(found->second, index);
        previous[values[index]] = index;
    }
    return std::nullopt;
}

lowerBound assumes ascending sorted values and returns the length if every value is smaller than the target. Duplicate matches move the upper boundary left instead of returning any equal midpoint. It takes logarithmic comparisons and constant auxiliary space. For production library code, std::lower_bound already provides an insertion-boundary operation; an interview implementation should still explain its invariant.

The Two Sum arithmetic assumes the conventional platform model where int values fit within the wider long long subtraction used here. On the course's ordinary 32-bit-int platforms, every difference of two ints fits. Do not generalize this implementation to arbitrary long long inputs without considering subtraction overflow separately.

Distinguish map lookup from insertion

unordered_map::find checks presence without creating a missing entry. Access through operator[] inserts a default-initialized mapped value for a missing key. That can be useful for incrementing a frequency but harmful when a lookup is supposed to leave the map unchanged.

A default index of zero is also indistinguishable from a legitimate zero index if you treat the returned value alone as a presence flag. The example compares the iterator with end, then reads the stored index. The lookup occurs before the current value is inserted, preserving the distinct-position requirement.

Unordered containers offer average constant-time lookup under the usual hashing assumptions, with linear worst-case operations. Ordered maps provide a different logarithmic-operation contract and ordered iteration. Name the structure you chose when stating the overall complexity; “a map is O(1)” omits both the implementation and the cost model. The unordered-container requirements specify the average and worst-case distinction.

Rehashing can invalidate iterators even when an insertion's logical result looks small. Do not retain a lookup iterator across later insertions unless the container's guarantees make that safe. Reading a copied index before mutation is often enough for a short algorithm.

Watch signed and unsigned boundaries

Container sizes are unsigned. Subtracting one from an empty size wraps in unsigned arithmetic; mixing that result with a signed loop variable can make a reverse loop surprising. A half-open loop or a reverse iterator avoids inventing an invalid last index.

Signed arithmetic overflow has its own language rules and should not be used as a normal wraparound mechanism. Promote operands before an operation when the result needs a wider type. Casting an already-overflowed result is too late. If every permitted input may already occupy the widest chosen signed type, use an explicit overflow check or another representation.

Bounds-checked access through at can help diagnose invalid indexes, while operator[] relies on the caller's valid-index invariant. Switching accessors does not repair an algorithm that discards the wrong half or visits a grid neighbor outside its dimensions.

Learn queue, heap, and string conventions

A std::queue provides FIFO processing through its adaptor interface. A default std::priority_queue exposes a maximum; a minimum-priority configuration uses an appropriate comparison such as std::greater. Choose heap orientation from which candidate must be inspected or evicted, especially for a bounded top-K set.

A std::string is a sequence of char elements. When those elements contain UTF-8, an index addresses a byte-sized code unit, not necessarily a complete Unicode code point. For ASCII-constrained exercises, byte traversal is sufficient. Arbitrary Unicode segmentation requires a specified representation and additional handling.

A fixed-size frequency array indexed by char also needs care on platforms where char is signed. A negative char value is not a valid direct array index. Make the alphabet constraint or an unsigned conversion explicit instead of relying on whichever inputs happened to be tested.

Test the assumptions you can name

For boundary search, test empty input, duplicates, a target before the first value, a missing middle target, and a target beyond the last value. Compare with std::lower_bound. For Two Sum, compare pair validity with exhaustive pairs on short arrays and include extreme int values, repeated values, no answer, and an index-zero answer.

Compile the examples with warnings enabled and practice running an address/undefined-behavior sanitizer when your environment supports it. Warnings do not prove correctness, but they can expose a signed comparison or invalid lifetime before a larger test hides it. Then work through First Bad Version, Count Islands, and the binary-search guide, preserving their stated input and output contracts.

Worked lesson walkthroughs

58 reading lessons with code examples in this language.

Concepts

Concept lesson

Arrays in C++

Learn array insertion in C++. 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 C++

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

Concept lesson

Hash Tables in C++

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

Concept lesson

Strings in C++

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

Concept lesson

Palindromes, permutations, and anagrams in C++

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

Concept lesson

Recursion in C++

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

Concept lesson

Logarithmic time in C++: repeated halving and search

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

Concept lesson

Binary search in C++: invariants and boundary tests

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

Concept lesson

Sorting in C++

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

Concept lesson

Linked Lists in C++

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

Concept lesson

Pointers in C++

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

Concept lesson

Queues in C++

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

Concept lesson

Stacks in C++

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

Concept lesson

Trees in C++

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

Concept lesson

Tree traversal in C++: in-order, pre-order, and post-order

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

Concept lesson

Binary Search Trees in C++

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

Concept lesson

Graphs in C++

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

Concept lesson

Depth-First Search in C++

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

Concept lesson

Breadth-First Search in C++

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

Concept lesson

Subproblems and Overlapping Subproblems in C++

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

Concept lesson

Memoization in C++

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

Concept lesson

Bottom-Up vs. Top-Down in C++

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

Concept lesson

Dynamic Programming in C++

Solve minimum coin count in C++. 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 C++

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

Implementation tutorial

Implement a hash table in C++: collisions, updates, and removal

Build a hash table in C++ 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 C++: head, tail, and node identity

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

Implementation tutorial

Implement a queue in C++: FIFO links and empty transitions

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

Implementation tutorial

Implement a stack in C++: push, pop, and ownership

Implement a linked stack in C++. 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 C++: insert and search

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

Implementation tutorial

Implement a graph in C++: adjacency lists and edge removal

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

Practice problems

Practice walkthrough

Two Sum in C++: all index pairs with unordered_map

Solve the all-pairs Two Sum exercise with unordered_map in C++. Preserve indexes, check complement range, and avoid insertion during lookup.

Practice walkthrough

Valid brackets in C++: a vector stack that preserves nesting

Use a vector as a stack to validate parentheses, brackets, and braces in C++. Guard empty access, ignore text, and test nesting.

Practice walkthrough

Product of array except self in C++: prefix and suffix products without division

Compute product of array except self with two C++ passes. Handle unsigned reverse indexing, zeros, input preservation, and signed overflow assumptions.

Practice walkthrough

Counting sort for ages in C++: worked solution

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

Practice walkthrough

Best stock profit in C++: one transaction

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

Practice walkthrough

Most frequent email in C++: hash-map solution

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

Practice walkthrough

First Bad Version in C++: boundary binary search

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

Practice walkthrough

Reverse a linked list in C++: pointer walkthrough

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

Practice walkthrough

Remove kth node from end in C++: zero-based deletion

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

Practice walkthrough

Merge sorted linked lists in C++: Combine Blockchains

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

Practice walkthrough

Count Islands in C++: DFS flood-fill walkthrough

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

Practice walkthrough

Validate a binary search tree in C++: inherited bounds

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

Practice walkthrough

Binary tree maximum depth in C++: count edges

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

Practice walkthrough

Lowest common ancestor in C++: return the original node

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

Practice walkthrough

Generate string permutations in C++: positional results

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

Practice walkthrough

Group palindrome permutations in C++: counts and keys

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

Practice walkthrough

Merge intervals in C++: Interview Scheduler

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

Practice walkthrough

Min-max stack in C++: constant-time extrema

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

Practice walkthrough

BFS shortest path in C++: Pilot a Rocket

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

Practice walkthrough

Maze reachability in C++: memoized down/right search

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

Practice walkthrough

Search a rotated sorted array in C++: Shifted Search

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

Practice walkthrough

Search a sorted matrix in C++: staircase walkthrough

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

Practice walkthrough

House Robber in C++: maximum nonadjacent sum

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

Practice walkthrough

Sum decimal digits in C++: recursive solution

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

Practice walkthrough

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

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

Practice walkthrough

Coin change in C++: minimum-coin dynamic programming

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

Practice walkthrough

Validate Sudoku in C++: rows, columns, and subsquares

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

Practice walkthrough

Spiral matrix traversal in C++: Walk a Matrix

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