title: Merge Strings Alternately slug: merge-strings-alternately difficulty: easy leetcode_id: 1768 leetcode_url: https://leetcode.com/problems/merge-strings-alternately/ categories: - strings - two-pointers patterns: - two-pointers function_signature: "def merge_alternately(word1: str, word2: str) -> str:" test_cases: visible: - input: { word1: "abc", word2: "pqr" } expected: "apbqcr" - input: { word1: "ab", word2: "pqrs" } expected: "apbqrs" - input: { word1: "abcd", word2: "pq" } expected: "apbqcd" hidden: - input: { word1: "a", word2: "b" } expected: "ab" - input: { word1: "a", word2: "xyz" } expected: "axyz" - input: { word1: "xyz", word2: "a" } expected: "xayz" - input: { word1: "hello", word2: "world" } expected: "hweolrllod" description: | You are given two strings `word1` and `word2`. Merge the strings by adding letters in alternating order, starting with `word1`. If a string is longer than the other, append the additional letters onto the end of the merged string. Return *the merged string*. constraints: | - `1 <= word1.length, word2.length <= 100` - `word1` and `word2` consist of lowercase English letters. examples: - input: 'word1 = "abc", word2 = "pqr"' output: '"apbqcr"' explanation: "The merged string is formed by alternating characters: a, p, b, q, c, r." - input: 'word1 = "ab", word2 = "pqrs"' output: '"apbqrs"' explanation: 'Since word2 is longer, "rs" is appended to the end after alternating through "ab" and "pq".' - input: 'word1 = "abcd", word2 = "pq"' output: '"apbqcd"' explanation: 'Since word1 is longer, "cd" is appended to the end after alternating through "ab" and "pq".' explanation: intuition: | Imagine you have two decks of cards and you want to shuffle them together by taking one card from each deck alternately. You pick a card from the first deck, then one from the second, then back to the first, and so on. When one deck runs out before the other, you simply place all the remaining cards from the longer deck on top. This problem works exactly the same way with strings. Think of each character as a card. We **interleave** characters from both strings one at a time, and when one string is exhausted, we append whatever remains from the other. The key insight is that we can process both strings simultaneously using either: 1. **Two pointers** - one for each string, advancing in lockstep 2. **Index-based iteration** - iterating up to the length of the longer string Since we're building a new string character by character, this is a straightforward linear traversal problem. approach: | We solve this using a **Two Pointers** approach: **Step 1: Initialise variables** - `result`: An empty list to collect characters (using a list is more efficient than string concatenation in Python) - `i`: Pointer starting at `0` to track position in both strings   **Step 2: Iterate while either string has characters** - Use a `while` loop that continues as long as `i` is less than either string's length - If `i < len(word1)`: append `word1[i]` to result - If `i < len(word2)`: append `word2[i]` to result - Increment `i` after each iteration   **Step 3: Return the merged result** - Join the list into a single string and return it   This approach naturally handles unequal string lengths. When one string is exhausted, only the remaining characters from the other string are appended. common_pitfalls: - title: String Concatenation in a Loop description: | In Python, using `result += char` inside a loop creates a new string object each time because strings are immutable. This leads to **O(n^2)** time complexity for building a string of length n. Instead, collect characters in a list and use `''.join()` at the end for O(n) performance. While this optimisation may seem unnecessary for small strings (up to 200 characters here), it's a good habit for larger inputs. wrong_approach: "result = result + word1[i] in a loop" correct_approach: "Append to a list, then ''.join() at the end" - title: Off-by-One Errors with Unequal Lengths description: | When iterating over two strings of different lengths, it's easy to accidentally index out of bounds. For example, if `word1 = "ab"` and `word2 = "pqrs"`, iterating to `max(len(word1), len(word2))` means indices 2 and 3 are valid for `word2` but not for `word1`. Always check `if i < len(word)` before accessing `word[i]`. wrong_approach: "Accessing word1[i] without bounds check" correct_approach: "Guard each access with if i < len(word)" - title: Forgetting to Handle Remaining Characters description: | A common mistake is stopping the loop when the shorter string ends, forgetting to append the remaining characters from the longer string. The condition `while i < len(word1) or i < len(word2)` ensures we continue until *both* strings are fully processed. wrong_approach: "while i < len(word1) and i < len(word2)" correct_approach: "while i < len(word1) or i < len(word2)" key_takeaways: - "**Two-pointer pattern**: When processing two sequences in parallel, use indices or pointers to track progress through each" - "**Handle unequal lengths gracefully**: Use `or` in loop conditions and bounds checks to avoid index errors" - "**String building efficiency**: In Python, prefer list accumulation with `join()` over repeated string concatenation" - "**Foundation for harder problems**: This interleaving pattern appears in merge operations (merge sort), zipper problems, and alternating data structures" time_complexity: "O(n + m). We iterate through each character of `word1` (length n) and `word2` (length m) exactly once." space_complexity: "O(n + m). We create a new string of length `n + m` to store the result." solutions: - approach_name: Two Pointers is_optimal: true code: | def merge_alternately(word1: str, word2: str) -> str: # Use a list for efficient character accumulation result = [] i = 0 # Continue while either string has characters left while i < len(word1) or i < len(word2): # Add character from word1 if available if i < len(word1): result.append(word1[i]) # Add character from word2 if available if i < len(word2): result.append(word2[i]) i += 1 # Join list into final string return ''.join(result) explanation: | **Time Complexity:** O(n + m) — We visit each character exactly once. **Space Complexity:** O(n + m) — The result string contains all characters from both inputs. We use a single index `i` to traverse both strings simultaneously. The `or` condition ensures we process all characters even when strings have different lengths. Bounds checking before each access prevents index errors. - approach_name: Itertools Zip Longest is_optimal: true code: | from itertools import zip_longest def merge_alternately(word1: str, word2: str) -> str: # zip_longest pairs characters, filling with '' when one string ends result = [] for c1, c2 in zip_longest(word1, word2, fillvalue=''): result.append(c1) result.append(c2) return ''.join(result) explanation: | **Time Complexity:** O(n + m) — Single pass through both strings. **Space Complexity:** O(n + m) — Result string stores all characters. Python's `zip_longest` pairs elements from both strings, using `''` (empty string) as a fill value when one string is shorter. This elegantly handles unequal lengths without explicit bounds checking. - approach_name: Two Separate Pointers is_optimal: false code: | def merge_alternately(word1: str, word2: str) -> str: result = [] i, j = 0, 0 # Alternate while both strings have characters while i < len(word1) and j < len(word2): result.append(word1[i]) result.append(word2[j]) i += 1 j += 1 # Append remaining characters from word1 while i < len(word1): result.append(word1[i]) i += 1 # Append remaining characters from word2 while j < len(word2): result.append(word2[j]) j += 1 return ''.join(result) explanation: | **Time Complexity:** O(n + m) — Each character visited once across the three loops. **Space Complexity:** O(n + m) — Result string contains all characters. This approach uses separate pointers `i` and `j` for each string. The first loop handles the interleaving, and the two remaining loops handle leftover characters. While slightly more verbose than the single-pointer approach, this pattern is useful when the two sequences need different handling during iteration.