Problem 859

Abstract / Summary

Two strings can be made equal by swapping two characters in one string if they are nearly identical with just one pair of differing characters.

Note

The full problem description, including helpful examples, can be found on LeetCode.

Python 0859.py

class Solution:
    def buddyStrings(self, s: str, goal: str) -> bool:
        if len(s) != len(goal):
            return False
        if len(s) <= 1:
            return False

        one = two = "?"
        for a, b in zip(s, goal):
            if a != b:
                if one == "?": # first mismatch
                    one = a
                    two = b
                else:
                    # second (or third) mismatch
                    if one != b or two != a:
                        return False
                    one = two = "!" # invalid characters so that third mismatch fails

        if one == "!":
            return True
        if one != "?":
            return False # one mismatch without a second mismatch

        # if no mismatch, then swap two identical characters
        return len(set(s)) < len(s)
26 lines | 863 bytes | submitted October 11, 2023 | GitHub   23% comment ratio | tab size 4 | moderate complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 34% (800k+ submissions).

Typical patterns to solve this problem:
  • Hash Table
  • String
I solved 663 easy, 1250 medium and 309 hard problems

AI Disclaimer

Every single line of code was written by me, 100% from scratch, between August 2023 and August 2024.
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.

See this dedicated page for more details.
LeetCode profile | GitHub repo

Code Walkthrough

Overview

The buddyStrings method determines whether two strings s and goal can be made identical by swapping exactly one pair of characters in s. It returns True when such a single swap exists and False otherwise. The implementation proceeds through a series of early checks, a single pass that records mismatched characters, and a final decision based on the recorded information.

Key Steps

Length Check

if len(s) != len(goal):
    return False

The function first verifies that the two strings share the same length. A mismatch in length makes any swap impossible, so the method returns immediately.

Early Return for Very Short Strings

if len(s) <= 1:
    return False

When the strings contain zero or one character, a swap cannot change the string, and the method exits early.

Mismatch Detection Loop

one = two = "?"
for a, b in zip(s, goal):
    if a != b:
        if one == "?":          # first mismatch
            one = a
            two = b
        else:
            # second (or third) mismatch
            if one != b or two != a:
                return False
            one = two = "!"     # mark that a valid swap was found

The loop iterates over paired characters from s and goal.

  • On the first mismatch, the characters are stored in one and two.
  • On a subsequent mismatch, the code checks whether the characters are the reverse of the first pair (one != b or two != a). If they are not, the strings cannot be fixed with a single swap and the function returns False.
  • When the second mismatch is the exact reverse, both placeholders are set to "!" to indicate that a valid swap has been identified and to cause any further mismatch to fail the later check.

Post-Loop Evaluation

if one == "!":
    return True
if one != "?":
    return False   # one mismatch without a second mismatch

After the loop, three situations are distinguished:

  • one == "!" means exactly two mismatches were found and they form a reversible pair, so the answer is True.
  • one != "?" (but not "!") indicates a single mismatch was recorded without a matching partner, leading to False.

Duplicate Character Check for Identical Strings

return len(set(s)) < len(s)

If no mismatches were recorded (one == "?"), the strings are already identical. In this case a swap can only succeed when s contains at least one repeated character, because swapping two identical characters leaves the string unchanged. The expression len(set(s)) < len(s) captures precisely that condition.

Edge Cases Handled

The implementation gracefully handles several boundary conditions:

  • Strings of different lengths are rejected immediately.
  • Strings of length zero or one cannot be altered by a swap, so they return False.
  • A single mismatched position leads to False because a single swap cannot fix a solitary difference.
  • Exactly two mismatched positions that are each other's counterpart result in True.
  • More than two mismatches trigger an early False when the third mismatch is encountered.
  • Identical strings are accepted only when a duplicate character exists, enabling a no-op swap of equal letters.
  • Identical strings without any repeated character correctly return False because any swap would change the string.

Performance Optimizations

The algorithm achieves its goal with a single linear pass over the input strings, avoiding any nested loops or repeated scans. Early exit points-such as the length check, the short-string guard, and the immediate return on an invalid second mismatch-prevent unnecessary work for inputs that can be decided quickly. The use of two simple placeholder variables (one and two) eliminates the need for auxiliary data structures during mismatch tracking. Only when the strings are completely identical does the code construct a set to test for duplicate characters; this operation is performed at most once and only on the original string, keeping the overall overhead minimal. The combination of early returns and minimal auxiliary storage ensures that the method runs efficiently even for long inputs.

written by openai gpt

ELI5 - Simplified Explanation

Imagine two boxes full of blocks, where each box is a word. You want to see if you can swap just two blocks in the first box to make it look exactly like the second box.

First, you check if the boxes have the same number of blocks. If one box is longer than the other, they can never match, so those boxes will not work. If a box has only one block, there is no second block to swap, so that also does not work.

Next, you look at the boxes side by side to find where the blocks are different. You keep track of the first pair of blocks that do not match. If you find a second pair that does not match, you check to see if swapping them makes the word look correct. If the swap fits perfectly, you mark that you are finished. If there are any other differences, or if the swap does not fix the mistake, the boxes cannot be made identical.

Finally, if you find no differences at all, you check if there are any duplicate letters in the first box. If there is at least one letter that appears twice, you can swap those two identical letters. Even though the swap happens, the word stays the same. If all the letters are unique, you are stuck because swapping any two would change the word.

written by google gemini

Code Quality

Several LLMs ranked my code quality on a scale from 1 (very poor) to 10 (outstanding):
n = 27 | median = 7 | μ = 7.15 | σ = 0.93

Complexity Analysis

Time: linear
As a rule of thumb, the maximum input size for one second execution time is
  • factorial: up to 10 elements
  • exponential: up to 20 elements
  • polynomial: a few thousand elements
  • loglinear: up to 100,000 elements
  • linear: a few million elements
  • logarithmic: a billion elements
  • constant: practically unlimited
generated automatically

Other Solutions

I wrote a basic crawler to find other solutions to that problem.
Obviously, I did that after I solved the problem myself.

In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.

And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.

(click on a column header to sort the table)
author
author solutions
www AlgoMonster C++ Python Java TS
WalkCCC C++ Python Java
leetcode.ca C++ Python Java Go TS
LeetcodeHelp C++ Python Java
Progiez C++ Python Java
github BigEggStudy C#
black-shadows C++
charles-wangkai Java
DimitrisJim C
everthis JS
fartem Ruby
fengvyi C++
fpdjsns C++
halfrost Go
haoel C++
JoshCrozier JS
keineahnung2345 C++
Krazune C++
lkwq007 Python
martianoff Scala
ruoru Rust
suxrobGM C#
trung-hn Python
varunu28 Java
YuriSpiridonov Python
zfang399 C++
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, Go, Java, Python, TypeScript
LeetcodeHelp C++, Java, Python
Progiez C++, Java, Python
BigEggStudy C#
black-shadows C++, C++
charles-wangkai Java
DimitrisJim C
everthis JavaScript
fartem Ruby
fengvyi C++
fpdjsns C++
halfrost Go
haoel C++
JoshCrozier JavaScript
keineahnung2345 C++
Krazune C++
lkwq007 Python
martianoff Scala
ruoru Rust
suxrobGM C#
trung-hn Python
varunu28 Java
YuriSpiridonov Python
zfang399 C++
39 links | 26 authors | 11 languages

Videos

4 videos   did my crawler come up with invalid videos ? drop me a line.

Similar Problems

1 similar problem

Solved On The Same Day

16 solutions   October 11, 2023

Extra

There are a few extra pages giving you some insights into my setup:
  • Tech Stack - my development environment and tools
  • AI - how AI helped me create this website (NOT solving the problems)
  • Progress - progression over time
  • Quality - code quality