Strings feel like their own special type, but under the hood a string is really just an array of characters — contiguous memory, index-based access, the same complexity rules apply. Understanding strings this way explains both why certain string operations are fast and why others are surprisingly slow traps for performance.

Strings Are Character Arrays

text = "hello"

# Index access -- O(1), exactly like an array
print(text[1])  # 'e'

# Length -- O(1) in most languages (the length is stored, not recounted)
print(len(text))

# Slicing -- O(k), where k is the length of the slice being copied
print(text[1:4])  # 'ell'

Output:

e
5
ell

The Key Difference: Immutability

In many languages — Python, Java, JavaScript — strings are immutable: once created, a string's contents can never be changed in place. What looks like "modifying" a string, like text += "!", actually creates a brand new string in memory and discards the old one. This is the source of a very common performance trap.

The String Concatenation Trap

# Slow: O(n^2) overall -- each += copies the ENTIRE string built so far
result = ""
for i in range(10000):
    result += str(i)   # creates a brand-new, slightly longer string every time

# Fast: O(n) overall -- collect pieces first, join once at the end
pieces = []
for i in range(10000):
    pieces.append(str(i))  # O(1) amortized, just adds to a list
result = "".join(pieces)   # O(n), one single pass to build the final string

Output:

Both approaches produce the same final string, but the first does roughly n copies of growing size (O(n) total characters copied each time, n times — O(n^2) overall), while the second does a single O(n) pass.

Each += in the first loop has to copy every character accumulated so far into a new block of memory, then add the next piece. Do that n times and you've turned what looks like a simple loop into an O(n²) operation — a classic example of why analyzing complexity matters even for code that "obviously" looks fine at a glance. Collecting pieces in a list and joining once avoids the repeated copying entirely.

Common String Operation Complexities

As a quick reference: index access and length are O(1); searching for a substring is typically O(n) (or O(n×m) with a naive approach, where m is the pattern length); slicing is O(k) for a slice of length k; and reversing or sorting characters requires building a new string, which is at least O(n). Keeping this mental model — "a string is an immutable array" — makes the performance characteristics of almost every string operation predictable rather than mysterious.