title: Add Binary slug: add-binary difficulty: easy leetcode_id: 67 leetcode_url: https://leetcode.com/problems/add-binary/ categories: - strings - math patterns: - two-pointers function_signature: "def add_binary(a: str, b: str) -> str:" test_cases: visible: - input: { a: "11", b: "1" } expected: "100" - input: { a: "1010", b: "1011" } expected: "10101" - input: { a: "0", b: "0" } expected: "0" hidden: - input: { a: "1", b: "1" } expected: "10" - input: { a: "111", b: "1" } expected: "1000" - input: { a: "1111", b: "1111" } expected: "11110" description: | Given two binary strings `a` and `b`, return *their sum as a binary string*. constraints: | - `1 <= a.length, b.length <= 10^4` - `a` and `b` consist only of `'0'` or `'1'` characters - Each string does not contain leading zeros except for the zero itself examples: - input: 'a = "11", b = "1"' output: '"100"' explanation: "In binary: 11 + 1 = 100 (which is 3 + 1 = 4 in decimal)." - input: 'a = "1010", b = "1011"' output: '"10101"' explanation: "In binary: 1010 + 1011 = 10101 (which is 10 + 11 = 21 in decimal)." explanation: intuition: | Think of this problem just like adding two numbers by hand in elementary school, but instead of base-10, we're working in base-2 (binary). When you add two decimal numbers on paper, you start from the rightmost digit, add the digits together along with any carry from the previous column, write down the result's last digit, and carry over anything that exceeds 9. Binary addition works exactly the same way, except we carry over when the sum exceeds 1. In binary: - `0 + 0 = 0` (no carry) - `0 + 1 = 1` (no carry) - `1 + 0 = 1` (no carry) - `1 + 1 = 10` (write `0`, carry `1`) - `1 + 1 + 1 = 11` (write `1`, carry `1`) The key insight is that we need to process both strings from right to left, handling cases where strings have different lengths and managing the carry throughout. approach: | We use a **Two Pointers from End** approach to simulate binary addition: **Step 1: Initialise pointers and carry** - `i`: Pointer starting at the last index of string `a` - `j`: Pointer starting at the last index of string `b` - `carry`: Set to `0` initially to track overflow from each addition - `result`: An empty list to collect result digits (we'll reverse at the end)   **Step 2: Process digits from right to left** - Continue while `i >= 0` OR `j >= 0` OR `carry > 0` - Get the current digit from `a` if `i >= 0`, otherwise use `0` - Get the current digit from `b` if `j >= 0`, otherwise use `0` - Calculate `total = digit_a + digit_b + carry` - Append `total % 2` to result (this is the current bit: `0` or `1`) - Update `carry = total // 2` (this is `1` if total >= 2, else `0`) - Decrement both pointers   **Step 3: Build and return the result** - Reverse the result list (since we built it backwards) - Join the digits into a string and return common_pitfalls: - title: Converting to Integers Directly description: | A tempting approach is to convert both strings to integers, add them, and convert back: ```python return bin(int(a, 2) + int(b, 2))[2:] ``` While this works for small inputs, it fails for very large binary strings. With lengths up to `10^4`, the resulting integer could have over 10,000 bits, which exceeds typical integer handling in some contexts and defeats the purpose of the exercise. The problem expects you to implement the addition algorithm manually. wrong_approach: "int(a, 2) + int(b, 2) conversion" correct_approach: "Manual digit-by-digit addition with carry" - title: Forgetting the Final Carry description: | After processing all digits, there may still be a carry left over. For example: - `a = "1"`, `b = "1"` should produce `"10"`, not `"0"` If you exit the loop only when both pointers are exhausted, you'll miss the final carry. The loop condition must include `carry > 0` to handle this case. wrong_approach: "while i >= 0 or j >= 0 (missing carry check)" correct_approach: "while i >= 0 or j >= 0 or carry > 0" - title: String Concatenation in Loop description: | Building the result by prepending characters to a string (`result = bit + result`) is O(n) per operation, leading to O(n^2) overall. Instead, append to a list and reverse at the end for O(n) total time. wrong_approach: "result = str(bit) + result in loop" correct_approach: "result.append(bit), then reverse" key_takeaways: - "**Two-pointer pattern**: When processing two sequences together, use two independent pointers that can move at their own pace" - "**Right-to-left processing**: For addition problems (decimal, binary, linked lists), always process from the least significant digit" - "**Carry handling**: The loop condition should include the carry to avoid missing the final overflow bit" - "**Foundation for related problems**: This technique applies to Add Strings (base-10), Add Two Numbers (linked lists), and Multiply Strings" time_complexity: "O(max(n, m)). We process each digit of both strings exactly once, where `n` and `m` are the lengths of `a` and `b`." space_complexity: "O(max(n, m)). The result string has at most `max(n, m) + 1` characters (the extra one for a possible final carry)." solutions: - approach_name: Two Pointers from End is_optimal: true code: | def add_binary(a: str, b: str) -> str: # Start from the rightmost digit of each string i, j = len(a) - 1, len(b) - 1 carry = 0 result = [] # Process while there are digits left or carry remains while i >= 0 or j >= 0 or carry: # Get current digit from a (or 0 if exhausted) digit_a = int(a[i]) if i >= 0 else 0 # Get current digit from b (or 0 if exhausted) digit_b = int(b[j]) if j >= 0 else 0 # Add digits plus carry total = digit_a + digit_b + carry # Current bit is total mod 2 (0 or 1) result.append(str(total % 2)) # Carry is 1 if total >= 2, else 0 carry = total // 2 # Move to next digit (left) i -= 1 j -= 1 # We built the result backwards, so reverse it return ''.join(reversed(result)) explanation: | **Time Complexity:** O(max(n, m)) — Single pass through both strings. **Space Complexity:** O(max(n, m)) — Result string storage. We simulate manual binary addition using two pointers starting from the end of each string. At each step, we add the current digits plus any carry, compute the result bit and new carry, then move left. The key is including `carry` in the loop condition to handle the final overflow. - approach_name: Bit Manipulation is_optimal: false code: | def add_binary(a: str, b: str) -> str: # Convert binary strings to integers x, y = int(a, 2), int(b, 2) # Use bit manipulation to add without + operator while y: # XOR gives sum without carry # AND shifted left gives the carry x, y = x ^ y, (x & y) << 1 return bin(x)[2:] # Convert back, strip '0b' prefix explanation: | **Time Complexity:** O(max(n, m)) — Each iteration removes one bit from the carry. **Space Complexity:** O(1) — Only integer variables used (excluding output). This approach uses bit manipulation: XOR computes the sum ignoring carries, while AND shifted left computes the carries. We repeat until no carries remain. Note: While elegant, this converts to integers first, which may not be the intended solution for very large inputs. Included here to demonstrate bit manipulation techniques.