DSA Tutorial
🔍

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

Python
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

FeatureStringCharacter Array
TypeObject/PrimitiveArray
MutabilityUsually ImmutableMutable
OperationsRich methodsManual indexing
MemoryOptimized (pooling)Raw array

String Creation

Different Ways to Create Strings

Python
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

Python
1s = "Hello" 2length = len(s) # 5 3 4# Empty string 5empty = "" 6print(len(empty)) # 0

Time Complexity: O(1) in most languages

2. Accessing Characters

Python
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

Python
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

Python
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

Python
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

Python
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") # 3

Time 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.

Python
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

Python
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

CharacterASCII ValueRange
'0' - '9'48 - 57Digits
'A' - 'Z'65 - 90Uppercase
'a' - 'z'97 - 122Lowercase
Space ' '32Whitespace

Useful Math:

  • 'a' - 'A' = 32 (convert case)
  • '0' = 48 (convert digit char to int: char - '0')

Common String Patterns

1. Reverse a String

Python
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

Python
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

OperationTimeSpaceNotes
Access charO(1)O(1)Direct indexing
LengthO(1)O(1)Stored value
ConcatenationO(n+m)O(n+m)Creates new string
SubstringO(k)O(k)k = substring length
ComparisonO(n)O(1)Lexicographic
SearchO(n×m)O(1)Naive algorithm
ReverseO(n)O(n)New string created
Upper/LowerO(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! 🚀

String Basics - Complete Guide