String Basics - Complete Guide
String Basics
Strings are one of the most fundamental data structures in programming. Understanding string operations is crucial for coding interviews and real-world applications.
What is a String?
A string is a sequence of characters. It's one of the most commonly used data types in programming.
"Hello, World!" ← String
['H','e','l','l','o'] ← Array of characters
Key Concept: In most languages, strings are either character arrays or immutable objects storing character sequences.
String Representation
Internal Storage
1# Python strings are immutable sequences
2s = "Hello"
3# Internally: array of Unicode code points
4# 'H' 'e' 'l' 'l' 'o'String vs Character Array
| Feature | String | Character Array |
|---|---|---|
| Type | Object/Primitive | Array |
| Mutability | Usually Immutable | Mutable |
| Operations | Rich methods | Manual indexing |
| Memory | Optimized (pooling) | Raw array |
String Creation
Different Ways to Create Strings
1# Python - multiple ways
2s1 = "Hello" # String literal
3s2 = 'World' # Single quotes work too
4s3 = """Multi
5line""" # Triple quotes for multiline
6s4 = str([1, 2, 3]) # Convert from other types
7s5 = "".join(['a','b']) # From list of chars
8
9# Empty string
10empty = ""Basic String Operations
1. Length / Size
1s = "Hello"
2length = len(s) # 5
3
4# Empty string
5empty = ""
6print(len(empty)) # 0Time Complexity: O(1) in most languages
2. Accessing Characters
1s = "Hello"
2
3# Access by index (0-based)
4first = s[0] # 'H'
5last = s[-1] # 'o' (negative indexing)
6second = s[1] # 'e'
7
8# Iterate over characters
9for char in s:
10 print(char)
11
12# Get character at index safely
13if len(s) > 10:
14 char = s[10]Time Complexity: O(1) for single character access
3. Substring / Slicing
1s = "Hello World"
2
3# Slicing [start:end] (end not included)
4sub1 = s[0:5] # "Hello"
5sub2 = s[6:11] # "World"
6sub3 = s[6:] # "World" (from 6 to end)
7sub4 = s[:5] # "Hello" (from start to 5)
8sub5 = s[:] # "Hello World" (copy)
9
10# Step slicing
11reverse = s[::-1] # "dlroW olleH" (reverse)
12every2 = s[::2] # "HloWrd" (every 2nd char)Time Complexity: O(k) where k = length of substring
4. Concatenation
1s1 = "Hello"
2s2 = "World"
3
4# Using + operator
5result = s1 + " " + s2 # "Hello World"
6
7# Using join (more efficient for multiple strings)
8words = ["Hello", "World", "!"]
9result = " ".join(words) # "Hello World !"
10
11# Using f-strings (Python 3.6+)
12name = "Alice"
13greeting = f"Hello, {name}!" # "Hello, Alice!"Time Complexity: O(n + m) where n, m are string lengths
Performance Note: For multiple concatenations in a loop, use StringBuilder (Java), list+join (Python), or array+join (JavaScript) for better performance.
5. String Comparison
1s1 = "Hello"
2s2 = "hello"
3s3 = "Hello"
4
5# Equality (case-sensitive)
6print(s1 == s3) # True
7print(s1 == s2) # False
8
9# Case-insensitive comparison
10print(s1.lower() == s2.lower()) # True
11
12# Lexicographic comparison
13print("apple" < "banana") # True (alphabetical)
14print("Apple" < "apple") # True (uppercase < lowercase in ASCII)Important: In Java, ALWAYS use .equals() for string comparison, not ==. The == operator checks reference equality, not content.
6. Searching in Strings
1s = "Hello World"
2
3# Find substring
4index = s.find("World") # 6 (returns -1 if not found)
5index2 = s.find("Python") # -1
6
7# Check if substring exists
8exists = "World" in s # True
9exists2 = "Python" in s # False
10
11# Find all occurrences
12text = "hello hello hello"
13indices = [i for i in range(len(text)) if text.startswith("hello", i)]
14
15# Count occurrences
16count = s.count("l") # 3Time Complexity: O(n × m) for naive search, where n = text length, m = pattern length
String Immutability
What is Immutability?
In many languages, strings are immutable - once created, they cannot be changed.
1# Python strings are IMMUTABLE
2s = "Hello"
3s[0] = 'h' # TypeError! Can't modify
4
5# Instead, create new string
6s = 'h' + s[1:] # "hello" (new string)
7
8# Original string unchanged
9original = "Hello"
10modified = original.lower()
11print(original) # Still "Hello"
12print(modified) # "hello"Why Immutability Matters
Advantages:
- ›Thread-safe: Can share between threads
- ›Caching: String pools save memory
- ›Security: Prevents accidental changes
- ›Hashable: Can use as hash map keys
Disadvantages:
- ›Performance: Concatenation in loops is slow
- ›Memory: Creates many intermediate strings
Best Practice: For heavy string manipulation (loops, building), use mutable builders (StringBuilder, list, etc.)
ASCII and Unicode
Character Encoding
1# Get ASCII/Unicode value
2char = 'A'
3value = ord(char) # 65
4
5# Get character from value
6char2 = chr(65) # 'A'
7
8# Example: Caesar cipher
9def caesar_shift(char, shift):
10 return chr((ord(char) - ord('a') + shift) % 26 + ord('a'))
11
12print(caesar_shift('a', 1)) # 'b'Common ASCII Values
| Character | ASCII Value | Range |
|---|---|---|
| '0' - '9' | 48 - 57 | Digits |
| 'A' - 'Z' | 65 - 90 | Uppercase |
| 'a' - 'z' | 97 - 122 | Lowercase |
| Space ' ' | 32 | Whitespace |
Useful Math:
- ›
'a' - 'A'= 32 (convert case) - ›
'0'= 48 (convert digit char to int:char - '0')
Common String Patterns
1. Reverse a String
1def reverse_string(s):
2 # Method 1: Slicing (Pythonic)
3 return s[::-1]
4
5# Method 2: Using reversed()
6def reverse_v2(s):
7 return ''.join(reversed(s))
8
9# Method 3: Two pointers (in-place on list)
10def reverse_v3(s):
11 chars = list(s)
12 left, right = 0, len(chars) - 1
13 while left < right:
14 chars[left], chars[right] = chars[right], chars[left]
15 left += 1
16 right -= 1
17 return ''.join(chars)Time: O(n), Space: O(1) for in-place, O(n) for new string
2. Check Palindrome
1def is_palindrome(s):
2 # Method 1: Compare with reverse
3 return s == s[::-1]
4
5# Method 2: Two pointers
6def is_palindrome_v2(s):
7 left, right = 0, len(s) - 1
8 while left < right:
9 if s[left] != s[right]:
10 return False
11 left += 1
12 right -= 1
13 return True
14
15# Method 3: Ignore non-alphanumeric (LeetCode style)
16def is_palindrome_v3(s):
17 # Remove non-alphanumeric and convert to lowercase
18 cleaned = ''.join(c.lower() for c in s if c.isalnum())
19 return cleaned == cleaned[::-1]Time: O(n), Space: O(1)
String Complexity Guide
| Operation | Time | Space | Notes |
|---|---|---|---|
| Access char | O(1) | O(1) | Direct indexing |
| Length | O(1) | O(1) | Stored value |
| Concatenation | O(n+m) | O(n+m) | Creates new string |
| Substring | O(k) | O(k) | k = substring length |
| Comparison | O(n) | O(1) | Lexicographic |
| Search | O(n×m) | O(1) | Naive algorithm |
| Reverse | O(n) | O(n) | New string created |
| Upper/Lower | O(n) | O(n) | New string created |
Key Takeaways
Strings are Immutable (in most languages)
- ›Modifications create new strings
- ›Use builders for heavy manipulation
- ›Concatenation in loops is expensive
Always Check Bounds
- ›Index out of range causes errors
- ›Use length checks before access
- ›Negative indices in Python work, but not all languages
Case Sensitivity
- ›"Hello" ≠ "hello"
- ›Use toLowerCase()/upper() for comparison
- ›ASCII: 'A' ≠ 'a' (differ by 32)
Common Patterns
- ›Two pointers for palindrome/reverse
- ›Hash map for character frequency
- ›Sliding window for substrings
- ›StringBuilder for concatenation
Master these basics before moving to advanced string algorithms! 🚀