Skip to content
DSA arrays 8 min read

Strings as Data Structures: Mutability Across Languages

A string is an ordered sequence of characters — essentially an array of characters with a friendlier interface. You can index into it, scan it, and measure its length in O(1) to O(n) just like an array. The one detail that trips people up across languages is mutability: whether you can change a string in place. Getting that right is the difference between fast code and accidental O(n²) blowups.

A string is a sequence of characters

At its core, "hello" is the characters h, e, l, l, o laid out in order, indexed from 0. Reading a character by index is O(1); reading the length is O(1) in all four languages.

#include <string>
std::string s = "hello";
char c = s[1];        // 'e' — O(1) access
int n = s.size();     // 5 — O(1)

The big difference: mutability

This is the part to internalize, because it changes how you write string algorithms in each language.

  • C++ std::string is mutable. You can assign s[i] = 'x' and modify characters in place. There’s also a char[] for low-level work.
  • Java String is immutable. Every “modification” creates a new object. To build or edit a string efficiently, use StringBuilder.
  • JavaScript strings are immutable. s[i] = 'x' silently does nothing. Build with an array of characters, then join.
  • Python str is immutable. s[i] = 'x' raises a TypeError. Convert to a list, edit, then "".join(...).

Here is the same task — change index 0 to an uppercase H — written idiomatically per language:

#include <string>
std::string s = "hello";
s[0] = 'H';            // mutable in place
// s is now "Hello"

Pitfall: Because Java, JavaScript, and Python strings are immutable, building a string by repeated += in a loop allocates a brand-new string each time — that’s O(n²) overall. Always accumulate into a StringBuilder / array / list and join once at the end for O(n).

Why immutability exists

Immutable strings can be shared safely across threads and used as hash keys without fear of changing underneath you. The trade-off is that edits cost a copy. C++ chooses raw control (mutable), while Java, JS, and Python choose safety (immutable) — neither is “better,” just different defaults you must respect.

Going deeper: Characters are not always one byte. ASCII fits in a byte, but Unicode characters may span multiple code units. Java char is a UTF-16 code unit, JavaScript indexes UTF-16 code units too, Python 3 str indexes Unicode code points, and C++ std::string indexes bytes. For most DSA problems (ASCII inputs) this doesn’t bite, but be aware on multilingual text.

Complexity of common operations

OperationComplexity
Access char by indexO(1)
LengthO(1)
Concatenate two strings (lengths a, b)O(a + b)
Substring of length mO(m)
Search for a pattern (length m)O(n · m) naive, O(n + m) with KMP
Compare two stringsO(min length)

Where to go next

Now that you know how strings behave, learn the everyday toolkit — splitting, joining, substrings, and character frequency — in string manipulation. Then test yourself with the string exercises.

Last updated June 25, 2026
Was this helpful?