Given two strings str1
and str2
of the same length, the task is to determine if str1
can be transformed into str2
using the following operation as many times as needed:
str1
and change all its occurrences to any other lowercase English character.Constraints:
str1
to the same character in str2
in a single operation.str1
and str2
consist only of lowercase English letters and are of equal length.
The goal is to return True
if it's possible to transform str1
into str2
using the allowed operations, or False
otherwise.
At first glance, it seems like you can always convert str1
to str2
by repeatedly replacing characters. However, the key constraints are:
str1
to the same character in str2
unless you use an intermediate character.
The brute-force way would be to try all possible transformation sequences, but that's inefficient. Instead, we can analyze the mapping from characters in str1
to str2
:
str1
would need to be mapped to more than one character in str2
, transformation is impossible.This leads us to a more optimized solution using character mapping and checking for cycles.
We solve the problem step-by-step as follows:
str1
is already equal to str2
, return True
.i
, map str1[i]
to str2[i]
.str1
maps to different characters in str2
at different positions, return False
.str2
) uses all 26 lowercase letters, and the mapping is a permutation, then there is no "spare" character to use as a temporary placeholder, so transformation is impossible. Return False
in this case.True
.
We use a hash map (dictionary) for efficient lookups and to ensure each character in str1
maps to only one character in str2
.
Let's use the example: str1 = "ab"
, str2 = "ba"
'a'
in str1
maps to 'b'
in str2
.'b'
in str1
maps to 'a'
in str2
.'a'
and 'b'
are used, but not all 26 letters are used. So, we can use an unused character (like 'c'
) as a temporary placeholder.'a'
to 'c'
: "cb"
'b'
to 'a'
: "ca"
'c'
to 'b'
: "ba"
"ab"
to "ba"
using allowed operations.Brute-force approach:
n
.The key insight is to model the transformation as a mapping of characters and to detect if a cycle prevents transformation due to lack of a spare character. By using a hash map to record mappings and a set to check for full alphabet usage, we can efficiently determine if the transformation is possible. This approach is both elegant and optimal, leveraging simple data structures and clear logic to solve the problem.
class Solution:
def canConvert(self, str1: str, str2: str) -> bool:
if str1 == str2:
return True
mapping = {}
for c1, c2 in zip(str1, str2):
if c1 in mapping:
if mapping[c1] != c2:
return False
else:
mapping[c1] = c2
# If all 26 characters are used as targets, no spare character for swap
return len(set(str2)) < 26
class Solution {
public:
bool canConvert(string str1, string str2) {
if (str1 == str2) return true;
unordered_map<char, char> mapping;
for (int i = 0; i < str1.size(); ++i) {
if (mapping.count(str1[i])) {
if (mapping[str1[i]] != str2[i]) return false;
} else {
mapping[str1[i]] = str2[i];
}
}
unordered_set<char> targets(str2.begin(), str2.end());
return targets.size() < 26;
}
};
class Solution {
public boolean canConvert(String str1, String str2) {
if (str1.equals(str2)) return true;
Map<Character, Character> mapping = new HashMap<>();
for (int i = 0; i < str1.length(); i++) {
char c1 = str1.charAt(i), c2 = str2.charAt(i);
if (mapping.containsKey(c1)) {
if (mapping.get(c1) != c2) return false;
} else {
mapping.put(c1, c2);
}
}
Set<Character> targets = new HashSet<>();
for (char c : str2.toCharArray()) targets.add(c);
return targets.size() < 26;
}
}
var canConvert = function(str1, str2) {
if (str1 === str2) return true;
let mapping = {};
for (let i = 0; i < str1.length; i++) {
let c1 = str1[i], c2 = str2[i];
if (c1 in mapping) {
if (mapping[c1] !== c2) return false;
} else {
mapping[c1] = c2;
}
}
let targets = new Set(str2);
return targets.size < 26;
};