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)
Difficulty
and has an acceptance rate of about 34% (800k+ submissions).
Typical patterns to solve this problem:
- Hash Table
- String
AI Disclaimer
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.
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
oneandtwo. - 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 returnsFalse. - 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 isTrue.one != "?"(but not"!") indicates a single mismatch was recorded without a matching partner, leading toFalse.
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
Falsebecause 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
Falsewhen 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
Falsebecause 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.
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.
Code Quality
Complexity Analysis
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
Other Solutions
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++ |
Videos
Similar Problems
- problem 1790: Check if One String Swap Can Make Strings Equal
Solved On The Same Day
- problem 914: X of a Kind in a Deck of Cards
- problem 925: Long Pressed Name
- problem 1346: Check If N and Its Double Exist
- problem 1805: Number of Different Integers in a String
- problem 1909: Remove One Element to Make the Array Strictly Increasing
- problem 2047: Number of Valid Words in a Sentence
- problem 2469: Convert the Temperature
- problem 2525: Categorize Box According to Criteria
- problem 2591: Distribute Money to Maximum Children
- problem 2614: Prime In Diagonal
- problem 2660: Determine the Winner of a Bowling Game
- problem 2760: Longest Even Odd Subarray With Threshold
- problem 2765: Longest Alternating Subarray
- problem 1255: Maximum Score Words Formed by Letters
- problem 2251: Number of Flowers in Full Bloom
Extra
- 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