Skip to content
← All posts

Check if One String Swap Can Make Strings Equal: Mismatch Counting Pattern

5 min read
leetcodeproblemeasystringshash-map

LeetCode Check if One String Swap Can Make Strings Equal asks you a deceptively simple question. Given two strings s1 and s2 of equal length, return true if you can make them equal by performing at most one string swap on exactly one of the strings. A swap trades the characters at two different indices within the same string.

The "at most" is important. If the strings are already equal, that counts too.

s1:0b1a2n3ks2:kanb
s1 = "bank", s2 = "kanb". Positions 0 and 3 differ. Swapping s2[0] and s2[3] gives "bank", matching s1.

Why this problem matters

This problem belongs to a family of "compare two strings character by character" questions. The pattern of walking through two strings in parallel, collecting positions where they differ, and then reasoning about those differences shows up repeatedly in string problems. Buddy Strings, Isomorphic Strings, and even Anagram-checking problems all rely on the same fundamental skill: structured character comparison.

The mismatch counting pattern is also a great example of reducing a problem to its core constraint. You do not need to actually perform the swap. You just need to figure out whether a valid swap could exist. That shift from simulation to analysis is something you will use in many other problems.

Finally, this is a clean example of early termination. The moment you find a third mismatch, you know the answer is false. You do not need to keep scanning. Recognizing when you can bail out early is a useful habit in both interviews and production code.

The key insight

Compare s1 and s2 character by character and collect the indices where they differ. There are only three possible outcomes:

  • Zero mismatches: the strings are already equal. Return true.
  • Exactly two mismatches at positions i and j: check if swapping those two characters in one string would make them match. That means s1[i] == s2[j] and s1[j] == s2[i]. If so, return true.
  • Any other number of mismatches (1, or 3+): return false. A single swap changes exactly two positions. One mismatch cannot be fixed by a swap (you would create a new mismatch at the other position). Three or more mismatches cannot all be resolved by one swap.

That is the entire logic. No sorting, no frequency maps, no recursion. Just count mismatches and verify the cross-match condition.

The solution

def are_almost_equal(s1: str, s2: str) -> bool:
    diffs = []
    for i in range(len(s1)):
        if s1[i] != s2[i]:
            diffs.append(i)
            if len(diffs) > 2:
                return False
    if len(diffs) == 0:
        return True
    if len(diffs) != 2:
        return False
    i, j = diffs
    return s1[i] == s2[j] and s1[j] == s2[i]

Here is what each part does:

  • Collect mismatches: walk through both strings in lockstep. Every time s1[i] != s2[i], record that index.
  • Early exit: if you ever find more than two mismatches, return false immediately. No need to keep scanning.
  • Zero mismatches: already equal. Return true.
  • Exactly one mismatch: impossible to fix with a swap. Return false.
  • Exactly two mismatches: verify the cross-match. If s1[i] matches s2[j] and s1[j] matches s2[i], swapping either pair makes the strings equal.

The early termination when len(diffs) > 2 is not just an optimization. It prevents the diffs list from growing unnecessarily on long strings. In the worst case, you still scan the full string (when there are 0 or 2 mismatches), but for many inputs you bail out after just a few characters.

Visual walkthrough

Example 1: Strings are already equal

s1:0a1b2cs2:abcAlready equal. Return true.

Zero mismatches. The strings already match, so no swap is needed. Return true.

Example 2: Exactly two mismatches, swap fixes it

s1:0b1a2n3ks2:kanbSwap s2[0] and s2[3]. Return true.

Positions 0 and 3 differ. s1[0]='b' matches s2[3]='b', and s1[3]='k' matches s2[0]='k'. One swap works.

Example 3: Exactly two mismatches, swap does not fix it

s1:0a1b2c3ds2:abdcSwap s2[2] and s2[3]. Return true.

Positions 2 and 3 differ. s1[2]='c' matches s2[3]='c', and s1[3]='d' matches s2[2]='d'. One swap works here too.

Example 4: More than two mismatches

s1:0a1b2c3d4es2:edcba4 mismatches. Cannot fix with one swap. Return false.

Four positions differ (0, 1, 3, 4). No single swap can fix more than two mismatched positions.

Example 5: Exactly one mismatch

s1:0a1b2c3ds2:abcf1 mismatch. Cannot fix with one swap. Return false.

Only position 3 differs. A swap always changes two positions, so one mismatch can never be resolved.

The walkthrough above covers every case: strings that already match, strings with exactly two fixable mismatches, and strings where a swap is not enough. Notice how the algorithm's logic maps directly to counting the red (mismatched) cells. Zero red cells means success. Two red cells means check the cross-match. Anything else means failure.

Complexity analysis

ApproachTimeSpace
Single pass comparisonO(n)O(1)

Time: O(n) where n is the length of the strings. You scan each character at most once, and the early exit means you often stop before reaching the end.

Space: O(1). The diffs list holds at most 2 elements before you either return or bail out. That is constant space regardless of input size.

This is optimal. You need to look at every character at least once to verify equality, so you cannot do better than O(n) time. And there is no auxiliary data structure that grows with input.

The building blocks

1. Character-by-character comparison

The foundation of this problem is the parallel scan: iterating through two strings of equal length and comparing characters at each index. This same operation appears in problems like Isomorphic Strings, Longest Common Prefix, and any problem that asks "how do these two sequences differ?"

for i in range(len(s1)):
    if s1[i] != s2[i]:
        # record or act on the mismatch

This template is worth having in your fingers. You will reach for it any time you need to find the positions or count of differences between two sequences.

2. Mismatch collection pattern

Instead of acting on each mismatch immediately, you collect them into a small list and reason about the list after the scan. This "collect then decide" pattern is cleaner than trying to handle every case inline, and it naturally supports problems where the answer depends on the total number of differences.

diffs = []
for i in range(len(s1)):
    if s1[i] != s2[i]:
        diffs.append(i)

You can add an early exit threshold to keep the list bounded, which turns this into a constant-space pattern for problems where only a small number of mismatches matter.

Edge cases

  • Already equal strings: zero mismatches, return true. No swap needed.
  • More than two mismatches: return false immediately. One swap cannot fix three or more positions.
  • Exactly one mismatch: return false. A swap always changes two positions, so you cannot fix just one.
  • Empty strings: two empty strings are equal. Return true. The loop body never executes.
  • Single character strings: if the characters match, return true. If they differ, that is one mismatch, which returns false.
  • Same characters but wrong positions: s1 = "ab", s2 = "ba". Two mismatches, and the cross-match holds. Return true.

From understanding to recall

This problem is easy to understand. The algorithm is short, the logic is clean, and the edge cases are manageable. But "easy to understand" does not mean "easy to reproduce under pressure." In an interview, you need the mismatch counting pattern to come to you automatically, without re-deriving the case analysis from scratch.

The trick is to practice the pattern, not just the problem. The character-by-character comparison and the "collect mismatches, then decide" template are reusable building blocks. Once those templates are automatic, you can adapt them to any problem that asks about differences between two sequences. Spaced repetition drills these templates into long-term memory so they fire on instinct.

Related posts

  • Buddy Strings - Similar swap-checking pattern with an additional twist around duplicate characters
  • Valid Anagram - Character frequency comparison between two strings
  • Isomorphic Strings - Another character mapping pattern between two strings

The mismatch counting approach in this problem is one of the simplest examples of reducing a string comparison to a small set of cases. Master it here, and you will recognize the same structure in harder problems where the case analysis is more involved but the core technique is identical.