Given two strings s1
and s2
of equal length, determine if you can make s1
equal to s2
by swapping exactly one pair of characters in s1
.
s1
and swap the characters at those positions.s1 == s2
already).true
if it's possible to make s1
equal to s2
with at most one swap, otherwise return false
.1 <= s1.length, s2.length <= 100
, s1.length == s2.length
, s1
and s2
consist of lowercase English letters.
The naive approach would be to try every possible pair of indices in s1
, swap them, and check if the result matches s2
. However, this is inefficient, especially for long strings.
Let's reason about the problem:
s1
is already equal to s2
, then no swaps are needed. But, we need to check if a swap is allowed (since the problem says "at most one swap", not "exactly one").s1
and s2
differ. If there are more than 2 differences, one swap can't fix all of them.s1
might make it equal to s2
. We need to check that the characters at those positions are "crossed" between the two strings.We can solve this problem in a few clear steps:
s1
is already equal to s2
, return true
. (Swapping is optional.)
s1
and s2
differ, check if swapping these two characters in s1
makes the strings equal.true
(no swap needed).false
(impossible with one swap).i
and j
, check that s1[i] == s2[j]
and s1[j] == s2[i]
.
This approach is efficient because we only need to scan the strings once, and all operations are constant time after that.
Let's consider the example: s1 = "bank"
, s2 = "kanb"
.
s1[0]
and s1[3]
makes s1
equal to s2
:
s1
becomes "kanb", which is exactly s2
.true
.
Another example: s1 = "attack"
, s2 = "defend"
.
false
.The key insight is that only two mismatches can be fixed with a single swap, and we can find those mismatches efficiently by a single scan. This approach is both simple and optimal, avoiding unnecessary swaps or brute-force checks. By focusing on the positions where the strings differ, we can quickly determine if a one-swap transformation is possible.
class Solution:
def areAlmostEqual(self, s1: str, s2: str) -> bool:
if s1 == s2:
return True
diff = []
for i in range(len(s1)):
if s1[i] != s2[i]:
diff.append(i)
if len(diff) > 2:
return False
if len(diff) != 2:
return False
i, j = diff
return s1[i] == s2[j] and s1[j] == s2[i]
class Solution {
public:
bool areAlmostEqual(string s1, string s2) {
if (s1 == s2) return true;
vector<int> diff;
for (int i = 0; i < s1.size(); ++i) {
if (s1[i] != s2[i])
diff.push_back(i);
if (diff.size() > 2)
return false;
}
if (diff.size() != 2)
return false;
int i = diff[0], j = diff[1];
return s1[i] == s2[j] && s1[j] == s2[i];
}
};
class Solution {
public boolean areAlmostEqual(String s1, String s2) {
if (s1.equals(s2)) return true;
List<Integer> diff = new ArrayList<>();
for (int i = 0; i < s1.length(); i++) {
if (s1.charAt(i) != s2.charAt(i))
diff.add(i);
if (diff.size() > 2)
return false;
}
if (diff.size() != 2)
return false;
int i = diff.get(0), j = diff.get(1);
return s1.charAt(i) == s2.charAt(j) && s1.charAt(j) == s2.charAt(i);
}
}
var areAlmostEqual = function(s1, s2) {
if (s1 === s2) return true;
let diff = [];
for (let i = 0; i < s1.length; i++) {
if (s1[i] !== s2[i])
diff.push(i);
if (diff.length > 2)
return false;
}
if (diff.length !== 2)
return false;
let [i, j] = diff;
return s1[i] === s2[j] && s1[j] === s2[i];
};