title: Check if One String Swap Can Make Strings Equal slug: check-if-one-string-swap-can-make-strings-equal difficulty: easy leetcode_id: 1790 leetcode_url: https://leetcode.com/problems/check-if-one-string-swap-can-make-strings-equal/ categories: - strings - hash-tables patterns: - two-pointers description: | You are given two strings `s1` and `s2` of equal length. A **string swap** is an operation where you choose two indices in a string (not necessarily different) and swap the characters at these indices. Return `true` *if it is possible to make both strings equal by performing **at most one string swap** on **exactly one** of the strings.* Otherwise, return `false`. constraints: | - `1 <= s1.length, s2.length <= 100` - `s1.length == s2.length` - `s1` and `s2` consist of only lowercase English letters. examples: - input: 's1 = "bank", s2 = "kanb"' output: "true" explanation: "Swap the first character with the last character of s2 to make \"bank\"." - input: 's1 = "attack", s2 = "defend"' output: "false" explanation: "It is impossible to make them equal with one string swap." - input: 's1 = "kelb", s2 = "kelb"' output: "true" explanation: "The two strings are already equal, so no string swap operation is required." explanation: intuition: | Think of this problem as finding **mismatches** between the two strings. Since we can only perform at most one swap, there's a strict limit on how different the strings can be. Imagine laying both strings side by side and comparing character by character. If they're already identical, we're done — no swap needed. If they differ at exactly two positions, we might be able to fix it with a single swap. But if they differ at more than two positions, no single swap can help. The key insight is this: for a single swap to work, the characters at the two mismatched positions must be **cross-matched**. If `s1[i] != s2[i]` and `s1[j] != s2[j]`, then swapping works only if `s1[i] == s2[j]` and `s1[j] == s2[i]`. Think of it like having two pairs of socks that got mixed up — you can only fix it if each sock from the first pair matches its counterpart in the second pair. approach: | We solve this by finding all positions where the strings differ and checking if a swap can fix them. **Step 1: Find all differing positions** - Iterate through both strings simultaneously - Track indices where `s1[i] != s2[i]` - Store these indices in a list called `diffs`   **Step 2: Analyse the number of differences** - If `len(diffs) == 0`: Strings are already equal, return `true` - If `len(diffs) != 2`: Cannot fix with exactly one swap, return `false` - A single swap affects exactly two positions, so we need exactly two differences   **Step 3: Verify the cross-match condition** - Let `i` and `j` be the two differing indices - Check if `s1[i] == s2[j]` and `s1[j] == s2[i]` - If both conditions hold, swapping positions `i` and `j` in either string makes them equal - Return the result of this check common_pitfalls: - title: Forgetting the Zero-Difference Case description: | When both strings are already equal, the answer is `true` — no swap is required. Some solutions incorrectly require exactly two differences, but the problem says "at most one" swap. Zero swaps is a valid solution when strings match. wrong_approach: "Requiring exactly 2 differences" correct_approach: "Accept 0 or 2 differences as valid" - title: Only Counting Differences Without Verifying Characters description: | Finding exactly two mismatched positions is necessary but not sufficient. For example, `s1 = "ab"` and `s2 = "cd"` have two differences, but swapping won't help because the characters don't match across positions. You must verify `s1[i] == s2[j]` and `s1[j] == s2[i]`. wrong_approach: "Only checking if there are exactly 2 differences" correct_approach: "Also verify the cross-match condition" - title: Checking for One Difference description: | If there's exactly one position where the strings differ, no single swap can fix it. A swap always affects two positions. Swapping two identical characters at the same position is allowed but doesn't help — you'd still have that one mismatch. wrong_approach: "Thinking one difference can be fixed by swapping" correct_approach: "Return false for exactly 1 difference" key_takeaways: - "**Count and verify**: When a problem asks about limited operations, count what needs to change and verify the operation can achieve it" - "**Cross-match pattern**: For swap-based problems, the key insight is often that elements must match in a crossed pattern" - "**Edge cases matter**: The zero-difference case (already equal) is easy to overlook but critical" - "**Simple iteration works**: Don't overcomplicate with hash maps when a single pass collecting indices suffices" time_complexity: "O(n). We traverse both strings once to find differing positions." space_complexity: "O(1). We store at most 2 indices in the differences list (we can early-exit if more)." solutions: - approach_name: Single Pass with Difference Tracking is_optimal: true code: | def are_almost_equal(s1: str, s2: str) -> bool: # Collect indices where characters differ diffs = [] for i in range(len(s1)): if s1[i] != s2[i]: diffs.append(i) # Early exit: more than 2 differences means impossible if len(diffs) > 2: return False # Case 1: Already equal (0 differences) if len(diffs) == 0: return True # Case 2: Exactly 1 difference — can't fix with a swap if len(diffs) == 1: return False # Case 3: Exactly 2 differences — check cross-match i, j = diffs[0], diffs[1] return s1[i] == s2[j] and s1[j] == s2[i] explanation: | **Time Complexity:** O(n) — Single pass through both strings. **Space Complexity:** O(1) — We store at most 2 indices. We iterate once, collecting positions where characters differ. With early exit when we find more than 2 differences, we ensure optimal performance. The final check verifies that swapping would actually make the strings equal. - approach_name: Direct Character Comparison is_optimal: true code: | def are_almost_equal(s1: str, s2: str) -> bool: # Find differing positions diffs = [i for i in range(len(s1)) if s1[i] != s2[i]] # Already equal if not diffs: return True # Must have exactly 2 differences for a swap to work if len(diffs) != 2: return False # Verify cross-match: swapping these positions would work i, j = diffs return s1[i] == s2[j] and s1[j] == s2[i] explanation: | **Time Complexity:** O(n) — List comprehension iterates through all characters. **Space Complexity:** O(n) in worst case — The list stores all differing indices. This is a more Pythonic version using list comprehension. While slightly less efficient (no early exit, stores all differences), it's cleaner for small inputs. The logic remains the same: find differences, check count, verify cross-match.