Arrays & Strings

Easy-Medium
Time: O(n) with hash map, O(n log n) with sortingSpace: O(n) for hash map, O(1) for in-place
0/30
problems solved
0%
1.

Introduction to Arrays & Strings

Arrays and Strings are the most fundamental data structures in programming. An array is a collection of elements stored in contiguous memory locations, while a string is essentially an array of characters.

Why are they important for interviews?

About 40% of coding interview questions involve arrays or strings. They test your ability to:

  • Think about edge cases (empty arrays, single elements)
  • Optimize time and space complexity
  • Use built-in methods efficiently
  • Apply various algorithmic techniques

Array Basics:

  • Access: O(1) - Direct access using index
  • Search: O(n) - Linear search, O(log n) if sorted (binary search)
  • Insert/Delete: O(n) - Need to shift elements
  • Space: O(n) - Stores n elements

String Basics:

  • Strings are immutable in most languages (Java, Python, JavaScript)
  • String concatenation in a loop is O(n²) - use StringBuilder/join instead
  • Character comparisons are O(1)
2.

The Hash Map Technique

The Hash Map is your best friend for array problems. It provides O(1) average time for lookups, insertions, and deletions.

When to use Hash Map:

  1. Finding pairs: Two Sum, finding complement
  2. Counting frequencies: Character count, duplicate detection
  3. Grouping elements: Group Anagrams, grouping by property
  4. Tracking seen elements: Contains Duplicate
  5. Storing prefix sums: Subarray sum problems

How it works:

Array: [2, 7, 11, 15], Target: 9
Step 1: Check if (9-2)=7 exists in map? No. Store {2: 0}
Step 2: Check if (9-7)=2 exists in map? Yes! Return [0, 1]

Time vs Space Tradeoff:

  • Without HashMap: O(n²) time, O(1) space (check all pairs)
  • With HashMap: O(n) time, O(n) space

This is a classic example of trading space for time efficiency.

Code
Java
3.

Interactive: Two Sum Hash Map Visualizer

Watch how the hash map stores values and finds complements in O(1) time.

Two Sum - Hash Map

O(n) solution using hash map for complement lookup

Speed:
Target: 9
Array:
2i=0
7i=1
11i=2
15i=3
Hash Map (value → index):
Click Play to find two numbers summing to 9

Key Insight: For each number, check if its complement (target - num) exists in the map. This trades O(n) space for O(1) lookup time.

4.

Frequency Counting Pattern

Counting how often each element appears is one of the most common array/string operations.

Common Use Cases:

  1. Valid Anagram: Check if two strings have same character frequencies
  2. Find duplicates: Count > 1 means duplicate
  3. Find majority element: Count > n/2
  4. First unique character: Count == 1

Visualization:

String: "anagram"
Building frequency map:
a: 1 -> a: 2 -> a: 3
n: 1
g: 1
r: 1
m: 1
Final: {a: 3, n: 1, g: 1, r: 1, m: 1}

For lowercase letters only, you can use an array of size 26 instead of HashMap:

  • More memory efficient
  • Slightly faster (no hashing overhead)
  • Index = character - 'a'
Code
Java
5.

Prefix Sum & Prefix Product

Prefix arrays let you answer range queries in O(1) time after O(n) preprocessing.

Prefix Sum: Store cumulative sum up to each index.

Array: [1, 2, 3, 4, 5]
Prefix Sum: [1, 3, 6, 10, 15]
Sum of range [1, 3] = prefix[3] - prefix[0] = 10 - 1 = 9
(elements 2 + 3 + 4 = 9) ✓

Prefix Product: Store cumulative product up to each index.

Array: [1, 2, 3, 4]
Prefix Prod: [1, 2, 6, 24]
Suffix Prod: [24, 24, 12, 4]
Product except self[i] = prefix[i-1] * suffix[i+1]

Key Insight for "Product Except Self":

  • Can't use division (zeros in array)
  • Solution: Multiply prefix product * suffix product
  • Can do in O(1) space by computing suffix on-the-fly
Code
Java
6.

Interactive: Prefix Sum Visualizer

Watch how prefix sums are built and used to answer range queries in O(1) time.

Prefix Sum Array

O(n) build, O(1) range sum queries

Speed:
Original Array:
10
21
32
43
54
Prefix Sum Array:
[ ]
Range Queries:
[1, 3]
[0, 4]
[2, 4]
Click Play to build prefix sum array

Formula: sum(l, r) = prefix[r] - prefix[l-1] (or prefix[r] if l=0)

7.

Kadane's Algorithm - Maximum Subarray

Kadane's Algorithm finds the maximum sum contiguous subarray in O(n) time. It's a beautiful example of dynamic programming.

The Key Insight: At each position, we make a simple decision:

  • Should we extend the previous subarray?
  • Or start a new subarray from here?

We extend if the previous sum is positive (it helps). We start fresh if it's negative (it hurts).

Visualization:

Array: [-2, 1, -3, 4, -1, 2, 1, -5, 4]
i=0: currentSum = -2, maxSum = -2
i=1: currentSum = max(1, -2+1) = 1, maxSum = 1
i=2: currentSum = max(-3, 1-3) = -2, maxSum = 1
i=3: currentSum = max(4, -2+4) = 4, maxSum = 4
i=4: currentSum = max(-1, 4-1) = 3, maxSum = 4
i=5: currentSum = max(2, 3+2) = 5, maxSum = 5
i=6: currentSum = max(1, 5+1) = 6, maxSum = 6 <- Answer!
i=7: currentSum = max(-5, 6-5) = 1, maxSum = 6
i=8: currentSum = max(4, 1+4) = 5, maxSum = 6
Maximum subarray sum = 6 (subarray [4, -1, 2, 1])

Formula: currentSum = max(nums[i], currentSum + nums[i])

Code
Java
8.

Interactive: Kadane's Algorithm Visualizer

See how Kadane's algorithm decides whether to extend or start a new subarray at each step.

Kadane's Algorithm

Find maximum subarray sum in O(n) time

Speed:
Current Sum: 0
Max Sum: -2
Array:
-2
1
-3
4
-1
2
1
-5
4
0
1
2
3
4
5
6
7
8
Click Play to find the maximum subarray sum
Current
Max Subarray

Key Insight: At each position, decide: extend previous subarray or start fresh? If previous sum is negative, starting fresh is always better.

9.

Subarray Sum Problems with HashMap

Many problems ask you to count or find subarrays with a specific sum. The key insight is using prefix sums with a HashMap.

Why does this work? If prefixSum[j] - prefixSum[i] = k, then the subarray from i+1 to j has sum k.

Visualization:

Array: [1, 2, 3, -2, 5], k = 5
Prefix sums: [0, 1, 3, 6, 4, 9]
^-- Include 0 for empty prefix
At index 2 (prefix=6): Is 6-5=1 in map? Yes! (index 0)
-> Subarray [1,2] to [2] = [2,3] sums to 5 ✓
At index 4 (prefix=9): Is 9-5=4 in map? Yes! (index 3)
-> Subarray [3] to [4] = [-2,5] sums to... wait, that's 3!
-> Actually [5] alone = 5 ✓

Key Points:

  1. Initialize map with {0: 1} for empty prefix
  2. For each position, check if (currentSum - k) exists
  3. Count how many times that prefix sum occurred
  4. Add current prefix sum to map
Code
Java
10.

Cyclic Sort - Index as Hash

When dealing with numbers in a specific range (1 to n), you can use the array indices themselves as a hash map. This gives O(1) space complexity!

The Idea: Place each number at its "correct" index:

  • Number 1 should be at index 0
  • Number 2 should be at index 1
  • Number k should be at index k-1

Visualization:

Array: [3, 4, -1, 1]
Step 1: nums[0]=3 should be at index 2
Swap: [3,4,-1,1] -> [-1,4,3,1]
Step 2: nums[0]=-1 is invalid, skip
Step 3: nums[1]=4 should be at index 3
Swap: [-1,4,3,1] -> [-1,1,3,4]
Step 4: nums[1]=1 should be at index 0
Swap: [-1,1,3,4] -> [1,-1,3,4]
Final: [1, -1, 3, 4]
Position 1 (index 1) doesn't have 2
-> First missing positive = 2

When to use:

  • Find missing number in range
  • Find duplicate in range
  • First missing positive
  • Find all duplicates/missing
Code
Java
11.

String Manipulation Techniques

Strings have their own set of patterns and gotchas. Here are the key techniques:

1. Two Pointer for Palindromes: Compare characters from both ends moving inward.

2. StringBuilder for Concatenation: Never concatenate strings in a loop - it's O(n²)!

3. Character Array for In-place: Convert to char[] to modify characters.

4. Sorting as a Key: Anagrams have the same sorted form.

5. ASCII/Unicode Values: Use character codes for calculations.

Common String Problems:

| Problem Type | Technique |
|---------------------|------------------------|
| Palindrome check | Two pointers |
| Anagram check | Frequency count |
| Pattern matching | KMP, Rabin-Karp |
| Longest substring | Sliding window |
| String permutation | Backtracking |
| Reverse words | Two-pass reverse |
Code
Java
12.

In-Place Array Modifications

Sometimes you need to modify an array without using extra space. This requires careful pointer manipulation.

Common Techniques:

1. Two-Pointer Swap: Used for partitioning, moving elements.

2. Overwrite from Start: Used for removing duplicates, filtering.

3. Reverse Sections: Used for rotating arrays.

Rotate Array Example:

Rotate [1,2,3,4,5,6,7] by k=3
Step 1: Reverse all -> [7,6,5,4,3,2,1]
Step 2: Reverse [0,k) -> [5,6,7,4,3,2,1]
Step 3: Reverse [k,n) -> [5,6,7,1,2,3,4] ✓

Remove Duplicates:

[1,1,2,2,2,3,3]
↑ Write pointer
↑ Read pointer
Keep unique elements at start:
[1,2,3,_,_,_,_]
Code
Java
13.

Comparison: Which Technique to Use?

Here's a decision guide for choosing the right technique:

Finding Elements:

GoalTechniqueTimeSpace
Find pair with sumHash MapO(n)O(n)
Find pair (sorted)Two PointersO(n)O(1)
Check if existsHash SetO(1)O(n)
Count occurrencesHash MapO(n)O(n)

Subarray Problems:

GoalTechniqueTime
Max sum subarrayKadane'sO(n)
Count subarrays with sum kPrefix Sum + MapO(n)
Max length with conditionSliding WindowO(n)

Modifying Arrays:

GoalTechniqueSpace
Remove duplicatesTwo PointersO(1)
Rotate arrayThree ReversesO(1)
Sort 0,1,2Dutch FlagO(1)

String Problems:

GoalTechnique
PalindromeTwo Pointers
AnagramFrequency Count
Substring searchSliding Window
Group anagramsSort as Key + Map

Remember:

  • O(n²) -> O(n): Usually needs HashMap or sorting
  • O(n) space -> O(1): Usually needs in-place techniques
  • Range queries: Consider prefix sum/product
  • Numbers in [1,n]: Consider cyclic sort

Test Your Knowledge

Take a quick 15question quiz to test what you've learned.