Skip to content
Hello Python
Data Structure1 Practice54 Interview

Array

Contiguous indexed sequence used for random access, scanning, and in-place transformations. This guide turns that contract into deliberate Python operations, interview invariants, and a runnable practice loop.

Recognize it when

Consider Array when the prompt's constraints and required operations match this shape: Contiguous indexed sequence used for random access, scanning, and in-place transformations.

Pybit studies a professional Array interview workspace with precise technical objects.
On this page · Mental Model

Checking your account…

Sign in to save your code and progress across devices. The lesson and problem statement remain public.

Array Code Labs

Mental Model

An interview “array” in Python is usually a list: an ordered sequence whose integer indices form a dense range from zero through len(values) - 1. Treat the index as part of the data model. A loop invariant should say what the processed prefix means, not merely that a loop counter moved.

For example, after processing values[:right], a result array might contain the answer for exactly those positions. That statement makes an off-by-one error visible: either right is already processed or it is the next position, but it cannot be both.

Python List Representation and Ownership

Python lists hold references to objects. Assignment creates another name for the same list; it does not copy the elements. A shallow copy creates a new outer list but still shares nested objects. In an interview, say whether the function may mutate its input before using an in-place technique.

The Python list documentation(opens in a new tab) defines the operations. Index reads and writes are constant-time operations. Appending is amortized O(1), while inserting or deleting near the front shifts later references and therefore costs O(n).

Update One Indexed Position

Reference
def replace_at(values, index, item):
    previous = values[index]
    values[index] = item
    return previous
Practice

Implement replace_at(values, index, item). Return the previous item and mutate exactly the requested list position without changing its length.

Public tests

  • Verify one indexed mutation
  • Preserve Python negative indexing

Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor

Indexed Access, Mutation, and Copying

Choose the operation whose cost matches the proof:

Operation Time Ownership effect
values[index] O(1) Reads the existing object reference
values[index] = item O(1) Mutates the original list through every alias
values.append(item) Amortized O(1) Mutates the original list
values.insert(0, item) O(n) Shifts every existing reference
values[start:end] O(k) Allocates a new outer list of k references
values.copy() O(n) Allocates a shallow outer copy

Slicing inside a loop can turn a linear-looking solution into quadratic work. Repeatedly creating values[:right] copies a growing prefix; prefer indices or a maintained aggregate when the algorithm only needs a boundary.

Separate a Copy from an Alias

Reference
def changed_copy(values, index, item):
    result = values.copy()
    result[index] = item
    return result
Practice

Implement changed_copy(values, index, item). Return a shallow outer copy with one replacement while leaving the original list unchanged.

Public tests

  • Verify copy ownership

Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor

Use an Index as State

When values come from a known dense domain, a list can replace a hash lookup. If every value is in 1..n, index value - 1 is a collision-free location for that label. The invariant is precise: after scanning a prefix, seen[i] is true exactly when i + 1 occurred in that prefix. A duplicate sets the same boolean again; it must not toggle the bit back to false.

Mark a Dense Value Domain

Reference
def mark_seen_indices(values):
    seen = [False] * len(values)
    for value in values:
        seen[value - 1] = True
    return seen
Practice

Implement mark_seen_indices(values). Values are integers from 1 through len(values). Return a boolean list whose index i is true exactly when i + 1 occurs.

Public tests

  • Verify dense index mapping
  • Verify duplicates do not toggle

Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor

Choose an Array or a Different Structure

Use a list when positions are dense, order matters, and indexed access or mutation dominates. Use a dictionary instead when keys are sparse or not integers. Use a deque rather than a list when the hot operation removes from the front. Use a set when only membership matters and no positional answer is required.

Sorting may expose useful order, but it changes positions and costs O(n log n). Before sorting, check whether the required answer includes original indices or whether a one-pass hash map preserves the needed information more directly.

Common Pitfalls

  • matrix = [[0] * columns] * rows aliases the same inner list; use a comprehension to allocate independent rows.
  • if target in values is O(n), not O(1); placing it inside a scan can produce O(n squared) work.
  • values = values + [item] allocates a new list, while append mutates the existing list.
  • Negative indices wrap from the end, so an accidental -1 can return a plausible but wrong value.

Explain It in an Interview

Before coding, state: “I will use the index as the stable identity of each position, and after each iteration the processed prefix has its final result.” While coding, call out whether the list is an input you may mutate, a fixed-size output buffer, or auxiliary state. At the end, count every full scan, slice, sort, insertion shift, and allocated list before giving time and space bounds.

The focused Mark Seen Indices(opens in a new tab) drill practices direct domain-to-index mapping. Product Except Self(opens in a new tab) then requires two directional invariants over the same dense positions without hiding an extra division or nested scan.

Python Version Note

Complexity & Invariants

Interview bounds depend on the stated representation, input model, and real Python operations.

OperationAverageWorstInterview note
Core Array workflowO(n)O(n)A bounded 1..n value domain can map directly into n array positions without a dictionary key lookup. After reading a value v, result[v - 1] is true and every previously marked position stays true.

Space

O(n) for the demonstrated Array workflow.

Assumptions

  • Exact bounds depend on copying, slicing, insertion position, and whether a new result is materialized.
  • The bound counts the operations in Mark Seen Indices and does not hide Python slicing, sorting, or copying.

Invariants Worth Saying Aloud

  1. State the precise Array invariant before coding and preserve it after every update, traversal step, or recursive return.
  2. A bounded 1..n value domain can map directly into n array positions without a dictionary key lookup. This remains true after every accepted operation.
  3. After reading a value v, result[v - 1] is true and every previously marked position stays true. This remains true after every accepted operation.

When To Use Or Avoid Array

Use It When

  • Use Array when its representation directly supports the prompt's repeated query or update.
  • Use it when the invariant can be stated before coding and preserved after every operation.

Choose Another Tool When

  • Avoid it when a simpler Python sequence or mapping communicates the same contract with less state.
  • Avoid it when building the structure costs more time or space than the number of required queries can justify.

Common Pitfalls

These are the mistakes most likely to survive a happy-path example and fail a boundary case.

Leaving the core transition unfinished

Placeholder code cannot preserve the Array invariant or satisfy the public contract.

Prevent it: Implement the smallest complete transition and run the public tests before adding optimizations.

Avoid

def mark_seen_indices(values):
    pass

Use instead

def mark_seen_indices(values):
    seen = [False] * len(values)
    for value in values:
        seen[value - 1] = True
    return seen

Breaking the central invariant

Toggles each mapped position, causing an even number of duplicate occurrences to look absent.

Prevent it: Keep this invariant visible while editing: State the precise Array invariant before coding and preserve it after every update, traversal step, or recursive return.

Avoid

def mark_seen_indices(values):
    seen = [False] * len(values)
    for value in values:
        seen[value - 1] = not seen[value - 1]
    return seen

Use instead

def mark_seen_indices(values):
    seen = [False] * len(values)
    for value in values:
        seen[value - 1] = True
    return seen

Hiding Python work inside the loop

Handle empty state, duplicate values, aliasing, and serialization boundaries explicitly in tests.

Prevent it: Account for every slice, copy, sort, membership test, and container mutation before claiming O(n).

Avoid

def mark_seen_indices(values):
    seen = [False] * len(values)
    for value in values:
        seen[value - 1] = not seen[value - 1]
    return seen

Use instead

def mark_seen_indices(values):
    seen = [False] * len(values)
    for value in values:
        seen[value - 1] = True
    return seen

Reviewed References

Official Python documentation supports language behavior. Canonical problem pages provide additional practice context.