Arrays & Strings

The most fundamental data structures. In Go, arrays are fixed-size and rarely used directly — slices are the standard dynamic array. Strings are immutable byte sequences with special handling for Unicode.

Go Slices (Dynamic Arrays)

Creation & Basics

// Literal
nums := []int{1, 2, 3}
 
// make(type, length, capacity)
nums := make([]int, 0, 10) // len=0, cap=10
 
// Append (may reallocate if cap exceeded)
nums = append(nums, 4)
 
// Slice of a slice (shares underlying array!)
sub := nums[1:3] // elements at index 1, 2

Complexity

OperationTimeNotes
Access by indexO(1)nums[i]
AppendO(1) amortizedO(n) when capacity doubles
Insert at indexO(n)Must shift elements right
Delete at indexO(n)Must shift elements left
Search (unsorted)O(n)Linear scan
Search (sorted)O(log n)Binary search
CopyO(n)copy(dst, src)

Internals

A slice header is a struct with three fields:

type slice struct {
    array unsafe.Pointer // pointer to underlying array
    len   int            // current length
    cap   int            // capacity before reallocation
}

Slice gotcha: shared backing array

Slicing (a[1:3]) creates a new slice header pointing to the same underlying array. Modifying one modifies the other. Use copy() if you need independence:

independent := make([]int, len(original))
copy(independent, original)

Growth Strategy

When append exceeds capacity, Go allocates a new array. The growth factor is roughly 2x for small slices, tapering off for large ones. Never rely on the exact capacity — always reassign: nums = append(nums, val).

Strings in Go

Strings are immutable sequences of bytes (not characters). For Unicode text, you need to work with runes.

s := "hello"
 
// Byte access (ASCII only safe)
b := s[0] // byte 'h'
 
// Rune iteration (Unicode safe)
for i, r := range s {
    // i = byte offset, r = rune (Unicode code point)
}
 
// String → byte slice (mutable copy)
bytes := []byte(s)
bytes[0] = 'H'
s2 := string(bytes) // "Hello"
 
// String → rune slice (for Unicode manipulation)
runes := []rune(s)

Bytes vs Runes rule of thumb

  • ASCII-only problems (LeetCode typically): s[i] is fine, len(s) gives character count
  • Unicode problems: convert to []rune first, or use range which decodes runes automatically

String Builder (efficient concatenation)

var sb strings.Builder
for _, word := range words {
    sb.WriteString(word)
}
result := sb.String()

Never concatenate strings in a loop with + — it allocates a new string every time (O(n²) total).

Common Array/String Patterns

  • Two Pointers — converging, expanding, or same-direction traversal
  • Sliding Window — maintain a window over a subarray/substring
  • Hash Tables — frequency counting, complement lookup
  • Sorting — sort then apply two pointers or binary search
  • Binary Search — O(log n) search in sorted arrays