1247. Minimum Swaps to Make Strings Equal
Problem Description
You have two strings s1
and s2
that are the same length and contain only the letters "x" and "y". Your goal is to make these two strings identical.
The only operation you can perform is swapping characters between the two strings - specifically, you can swap s1[i]
with s2[j]
where i
and j
can be any valid positions. Note that you can only swap characters that are in different strings (you cannot swap two characters within the same string).
For example:
- If
s1 = "xy"
ands2 = "yx"
, you could swaps1[0]
withs2[0]
to gets1 = "yy"
ands2 = "xx"
, then swaps1[1]
withs2[1]
to gets1 = "yx"
ands2 = "xy"
, and continue swapping until both strings are equal.
The task is to find the minimum number of swaps needed to make s1
and s2
equal. If it's impossible to make them equal through any sequence of swaps, return -1
.
The key insight is that when s1[i] ≠ s2[i]
, we have mismatches that need to be resolved. We can categorize these mismatches as:
xy
type: wheres1[i] = 'x'
ands2[i] = 'y'
yx
type: wheres1[i] = 'y'
ands2[i] = 'x'
Two mismatches of the same type can be resolved with one swap (e.g., two xy
pairs can be fixed with one swap), while two mismatches of different types require two swaps. If the total number of mismatches is odd, it's impossible to make the strings equal.
Intuition
Let's think about what happens when we encounter mismatches between the two strings. When s1[i] ≠ s2[i]
, we need to fix this mismatch somehow through swaps.
Consider the types of mismatches we can have:
- Type
xy
: positioni
hass1[i] = 'x'
ands2[i] = 'y'
- Type
yx
: positioni
hass1[i] = 'y'
ands2[i] = 'x'
Now, let's see how we can resolve these mismatches:
Case 1: Two mismatches of the same type
-
If we have two
xy
mismatches at positionsi
andj
:s1[i] = 'x'
,s2[i] = 'y'
s1[j] = 'x'
,s2[j] = 'y'
- We can swap
s1[i]
withs2[j]
, resulting in both positions becoming matched - This takes only 1 swap to fix 2 mismatches
-
Similarly for two
yx
mismatches, we need only 1 swap
Case 2: One xy
mismatch and one yx
mismatch
- We have:
- Position
i
:s1[i] = 'x'
,s2[i] = 'y'
- Position
j
:s1[j] = 'y'
,s2[j] = 'x'
- Position
- We need 2 swaps to fix these:
- First swap
s1[i]
withs2[i]
to get twoyx
mismatches - Then use 1 more swap to fix the two
yx
mismatches (as in Case 1)
- First swap
The key observation is that mismatches always come in pairs that can be resolved together. If we have an odd total number of mismatches (xy + yx
is odd), it's impossible to resolve all of them since we can't pair them all up.
For the minimum number of swaps:
- Every pair of same-type mismatches needs 1 swap
- Every remaining mixed pair (
xy
withyx
) needs 2 swaps - This gives us:
xy // 2 + yx // 2
(for same-type pairs) +xy % 2 + yx % 2
(for the remaining mixed pair if any)
Solution Approach
The implementation follows a greedy approach based on counting mismatches:
-
Count the mismatches: We iterate through both strings simultaneously using
zip(s1, s2)
and count two types of mismatches:xy
: whens1[i] = 'x'
ands2[i] = 'y'
, which occurs whena < b
(since 'x' < 'y' in ASCII)yx
: whens1[i] = 'y'
ands2[i] = 'x'
, which occurs whena > b
(since 'y' > 'x' in ASCII)
-
Check feasibility: If the total number of mismatches
(xy + yx)
is odd, it's impossible to make the strings equal, so we return-1
. This is because mismatches must be resolved in pairs, and an odd count means one mismatch will remain unpaired. -
Calculate minimum swaps: When the total is even, we calculate the minimum number of swaps:
xy // 2
: Number of swaps needed to fix pairs ofxy
mismatches (each pair needs 1 swap)yx // 2
: Number of swaps needed to fix pairs ofyx
mismatches (each pair needs 1 swap)xy % 2 + yx % 2
: If there's one remainingxy
and one remainingyx
mismatch after pairing same-type mismatches, they form a mixed pair that needs 2 swaps total
The formula xy // 2 + yx // 2 + xy % 2 + yx % 2
elegantly captures this logic:
- When both
xy
andyx
are even, we only needxy // 2 + yx // 2
swaps - When both are odd, we have one leftover of each type forming a mixed pair, adding 2 more swaps (
xy % 2 + yx % 2 = 1 + 1 = 2
) - When one is odd and one is even, the total would be odd, which we've already handled by returning
-1
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through an example with s1 = "xxxy"
and s2 = "yyyx"
.
Step 1: Identify mismatches Comparing position by position:
- Position 0:
s1[0] = 'x'
,s2[0] = 'y'
→xy
mismatch - Position 1:
s1[1] = 'x'
,s2[1] = 'y'
→xy
mismatch - Position 2:
s1[2] = 'x'
,s2[2] = 'y'
→xy
mismatch - Position 3:
s1[3] = 'y'
,s2[3] = 'x'
→yx
mismatch
Count: xy = 3
, yx = 1
Step 2: Check if solution is possible
Total mismatches = 3 + 1 = 4
(even), so a solution exists.
Step 3: Calculate minimum swaps
Using the formula: xy // 2 + yx // 2 + xy % 2 + yx % 2
xy // 2 = 3 // 2 = 1
(one pair ofxy
mismatches)yx // 2 = 1 // 2 = 0
(no pairs ofyx
mismatches)xy % 2 = 3 % 2 = 1
(one leftoverxy
mismatch)yx % 2 = 1 % 2 = 1
(one leftoveryx
mismatch)- Total:
1 + 0 + 1 + 1 = 3
swaps
Step 4: Verify with actual swaps
-
Fix two
xy
mismatches with one swap: Swaps1[0]
withs2[1]
- Result:
s1 = "yxxy"
,s2 = "xyyx"
- Remaining mismatches at positions 1 (
yx
) and 3 (yx
)
- Result:
-
Fix the two
yx
mismatches with one swap: Swaps1[1]
withs2[3]
- Result:
s1 = "yxxy"
,s2 = "xyyx"
→s1 = "yxxx"
,s2 = "xyyy"
- Wait, let me recalculate...
- Result:
Actually, let me trace through more carefully:
- Initial:
s1 = "xxxy"
,s2 = "yyyx"
- Swap
s1[0]
withs2[1]
:s1 = "yxxy"
,s2 = "yxyx"
- Now positions 1 and 3 have
yx
mismatches. Swaps1[1]
withs2[3]
:s1 = "yyyy"
,s2 = "xxxx"
- Still mismatched! We need one more swap: Swap
s1[0]
withs2[0]
:s1 = "xyyy"
,s2 = "xyyy"
✓
The algorithm correctly predicted 3 swaps would be needed.
Solution Implementation
1class Solution:
2 def minimumSwap(self, s1: str, s2: str) -> int:
3 # Count mismatches where s1[i] = 'x' and s2[i] = 'y'
4 x_y_mismatch_count = 0
5 # Count mismatches where s1[i] = 'y' and s2[i] = 'x'
6 y_x_mismatch_count = 0
7
8 # Iterate through both strings simultaneously
9 for char1, char2 in zip(s1, s2):
10 # When char1 is 'x' and char2 is 'y' (since 'x' < 'y')
11 x_y_mismatch_count += char1 < char2
12 # When char1 is 'y' and char2 is 'x' (since 'y' > 'x')
13 y_x_mismatch_count += char1 > char2
14
15 # If total mismatches is odd, it's impossible to make strings equal
16 if (x_y_mismatch_count + y_x_mismatch_count) % 2:
17 return -1
18
19 # Calculate minimum swaps needed:
20 # - Each pair of same type mismatches needs 1 swap (xy-xy or yx-yx)
21 # - Remaining unpaired mismatches (one xy and one yx) need 2 swaps
22 return (x_y_mismatch_count // 2 +
23 y_x_mismatch_count // 2 +
24 x_y_mismatch_count % 2 +
25 y_x_mismatch_count % 2)
26
1class Solution {
2 public int minimumSwap(String s1, String s2) {
3 // Count mismatches where s1 has 'x' and s2 has 'y' (xy pattern)
4 int xyMismatchCount = 0;
5 // Count mismatches where s1 has 'y' and s2 has 'x' (yx pattern)
6 int yxMismatchCount = 0;
7
8 // Iterate through both strings to count mismatches
9 for (int i = 0; i < s1.length(); i++) {
10 char charFromS1 = s1.charAt(i);
11 char charFromS2 = s2.charAt(i);
12
13 // When s1[i] = 'x' and s2[i] = 'y' (since 'x' < 'y' in ASCII)
14 if (charFromS1 < charFromS2) {
15 xyMismatchCount++;
16 }
17
18 // When s1[i] = 'y' and s2[i] = 'x' (since 'y' > 'x' in ASCII)
19 if (charFromS1 > charFromS2) {
20 yxMismatchCount++;
21 }
22 }
23
24 // If total number of mismatches is odd, impossible to make strings equal
25 if ((xyMismatchCount + yxMismatchCount) % 2 == 1) {
26 return -1;
27 }
28
29 // Calculate minimum swaps needed:
30 // - xy/2 pairs can be fixed with xy/2 swaps (swap within same type)
31 // - yx/2 pairs can be fixed with yx/2 swaps (swap within same type)
32 // - Remaining unpaired xy and yx (if any) need 2 swaps to fix
33 return xyMismatchCount / 2 + yxMismatchCount / 2 + xyMismatchCount % 2 + yxMismatchCount % 2;
34 }
35}
36
1class Solution {
2public:
3 int minimumSwap(string s1, string s2) {
4 // Count mismatches of each type
5 // xy_count: positions where s1[i] = 'x' and s2[i] = 'y'
6 // yx_count: positions where s1[i] = 'y' and s2[i] = 'x'
7 int xy_count = 0;
8 int yx_count = 0;
9
10 // Iterate through both strings simultaneously
11 for (int i = 0; i < s1.size(); ++i) {
12 char char_from_s1 = s1[i];
13 char_from_s2 = s2[i];
14
15 // When s1 has 'x' and s2 has 'y' (since 'x' < 'y' in ASCII)
16 if (char_from_s1 < char_from_s2) {
17 xy_count++;
18 }
19 // When s1 has 'y' and s2 has 'x' (since 'y' > 'x' in ASCII)
20 else if (char_from_s1 > char_from_s2) {
21 yx_count++;
22 }
23 // Characters are already equal, no swap needed
24 }
25
26 // If total mismatches is odd, impossible to make strings equal
27 if ((xy_count + yx_count) % 2 != 0) {
28 return -1;
29 }
30
31 // Calculate minimum swaps needed:
32 // - Each pair of same type mismatches needs 1 swap (xy/2 + yx/2)
33 // - Remaining unpaired mismatches need 2 swaps (xy%2 + yx%2)
34 return (xy_count / 2) + (yx_count / 2) + (xy_count % 2) + (yx_count % 2);
35 }
36};
37
1/**
2 * Calculates the minimum number of swaps needed to make two strings equal
3 * @param s1 - First string containing only 'x' and 'y' characters
4 * @param s2 - Second string containing only 'x' and 'y' characters
5 * @returns The minimum number of swaps needed, or -1 if impossible
6 */
7function minimumSwap(s1: string, s2: string): number {
8 // Count mismatches where s1 has 'x' and s2 has 'y'
9 let countXY: number = 0;
10 // Count mismatches where s1 has 'y' and s2 has 'x'
11 let countYX: number = 0;
12
13 // Iterate through both strings to count mismatches
14 for (let i = 0; i < s1.length; i++) {
15 const charFromS1: string = s1[i];
16 const charFromS2: string = s2[i];
17
18 // When s1[i] < s2[i], it means s1 has 'x' and s2 has 'y' (since 'x' < 'y')
19 countXY += charFromS1 < charFromS2 ? 1 : 0;
20
21 // When s1[i] > s2[i], it means s1 has 'y' and s2 has 'x' (since 'y' > 'x')
22 countYX += charFromS1 > charFromS2 ? 1 : 0;
23 }
24
25 // If total number of mismatches is odd, it's impossible to make strings equal
26 if ((countXY + countYX) % 2 !== 0) {
27 return -1;
28 }
29
30 // Calculate minimum swaps:
31 // - Each pair of same-type mismatches (xx-yy or yy-xx) needs 1 swap
32 // - Remaining mismatches (one xy and one yx) need 2 swaps
33 return Math.floor(countXY / 2) + Math.floor(countYX / 2) + (countXY % 2) + (countYX % 2);
34}
35
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the strings s1
and s2
. This is because the algorithm iterates through both strings once using zip(s1, s2)
, performing constant-time operations (comparisons and arithmetic) for each pair of characters.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space for the two counter variables xy
and yx
, regardless of the input size. The zip
function creates an iterator that doesn't store all pairs in memory at once, so it doesn't contribute to space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding the Swap Operation
A common mistake is thinking you can swap characters within the same string (like swapping s1[i]
with s1[j]
). The problem explicitly states you can only swap between the two strings - s1[i]
with s2[j]
.
Wrong approach:
# Trying to swap within the same string if s1[i] != s1[j]: s1[i], s1[j] = s1[j], s1[i] # This is NOT allowed!
Correct understanding:
# Can only swap between s1 and s2 s1[i], s2[j] = s2[j], s1[i] # This is allowed
2. Incorrectly Counting Character Frequencies
Some might try to solve this by just counting total 'x' and 'y' characters across both strings, thinking if the counts match, the strings can be made equal.
Wrong approach:
def minimumSwap(self, s1: str, s2: str) -> int:
total_x = s1.count('x') + s2.count('x')
total_y = s1.count('y') + s2.count('y')
if total_x % 2 != 0 or total_y % 2 != 0:
return -1
# This misses the actual mismatch positions!
Why it's wrong: Even if total counts are even, the specific positions of mismatches matter. For example, s1 = "xx", s2 = "yy"
has even counts but requires 2 swaps, while s1 = "xy", s2 = "xy"
has the same counts but requires 0 swaps.
3. Forgetting the Mixed Pair Case
When implementing the solution, it's easy to only consider same-type mismatch pairs and forget that one remaining xy
mismatch and one remaining yx
mismatch can be resolved together with 2 swaps.
Incomplete solution:
def minimumSwap(self, s1: str, s2: str) -> int:
xy, yx = 0, 0
for c1, c2 in zip(s1, s2):
if c1 == 'x' and c2 == 'y':
xy += 1
elif c1 == 'y' and c2 == 'x':
yx += 1
# Wrong: Only considering same-type pairs
if xy % 2 != 0 or yx % 2 != 0:
return -1
return xy // 2 + yx // 2
Correct approach: The solution handles this by checking if the total count is even (not individual counts) and adds the extra swaps for mixed pairs: xy % 2 + yx % 2
.
4. Using String Comparison Instead of Character Comparison
The clever use of char1 < char2
and char1 > char2
might be misimplemented if not careful about what's being compared.
Potential mistake:
# Comparing entire strings instead of characters if s1 < s2: # This compares entire strings lexicographically! xy += 1
Correct implementation:
for char1, char2 in zip(s1, s2):
xy += char1 < char2 # Compares individual characters
yx += char1 > char2
Which algorithm should you use to find a node that is close to the root of the tree?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!