You are given two strings, word1
and word2
. Your task is to determine if these two strings are "close" under the following operations:
Two strings are considered "close" if you can make them equal using any number of these operations. The constraints are:
Return true
if word1
and word2
are close, and false
otherwise.
At first glance, the problem seems similar to checking if two strings are anagrams. However, the allowed operations let us do more than just rearrange characters: we can also swap all instances of one letter with another, which changes the distribution of letters.
The brute-force approach would be to generate all possible strings from word1
using the allowed operations and see if word2
can be obtained. But this is computationally infeasible for large strings.
The key insight is to focus on the properties that are preserved by the allowed operations:
Thus, the problem reduces to checking two things:
To solve the problem efficiently, we follow these steps:
word1
and word2
. This can be done using a hash map or array (since only lowercase English letters are used).
false
.
true
; otherwise, return false
.
Why does this work? Because the allowed operations let us permute the frequencies among the existing characters, but not introduce or remove characters. So, if both the sets of unique characters and the sorted frequency lists match, the transformation is possible.
Let's walk through an example with word1 = "abbzzca"
and word2 = "babzcaz"
.
word1
: a:2, b:2, c:1, z:2 word2
: b:2, a:2, z:2, c:1
true
.
For a negative example, word1 = "aabbcc"
and word2 = "aabbc"
:
false
.Brute-force approach: Generating all possible transformations is factorial in string length and infeasible for large inputs.
Optimized approach:
The solution is efficient and scalable for long strings.
The "Determine if Two Strings Are Close" problem tests your understanding of string manipulation under specific operations. The key insight is that the allowed operations preserve the set of unique characters and allow permutation of their frequencies. By checking these two properties, we can efficiently determine if one string can be transformed into the other, making the solution both elegant and optimal.
from collections import Counter
class Solution:
def closeStrings(self, word1: str, word2: str) -> bool:
count1 = Counter(word1)
count2 = Counter(word2)
# Check if unique character sets are equal
if set(count1.keys()) != set(count2.keys()):
return False
# Check if sorted frequencies are equal
return sorted(count1.values()) == sorted(count2.values())
#include <string>
#include <vector>
#include <algorithm>
#include <unordered_set>
using namespace std;
class Solution {
public:
bool closeStrings(string word1, string word2) {
vector<int> freq1(26, 0), freq2(26, 0);
unordered_set<char> set1, set2;
for (char c : word1) {
freq1[c - 'a']++;
set1.insert(c);
}
for (char c : word2) {
freq2[c - 'a']++;
set2.insert(c);
}
if (set1 != set2) return false;
sort(freq1.begin(), freq1.end());
sort(freq2.begin(), freq2.end());
return freq1 == freq2;
}
};
import java.util.*;
class Solution {
public boolean closeStrings(String word1, String word2) {
int[] freq1 = new int[26];
int[] freq2 = new int[26];
Set<Character> set1 = new HashSet<>();
Set<Character> set2 = new HashSet<>();
for (char c : word1.toCharArray()) {
freq1[c - 'a']++;
set1.add(c);
}
for (char c : word2.toCharArray()) {
freq2[c - 'a']++;
set2.add(c);
}
if (!set1.equals(set2)) return false;
Arrays.sort(freq1);
Arrays.sort(freq2);
return Arrays.equals(freq1, freq2);
}
}
var closeStrings = function(word1, word2) {
if (word1.length !== word2.length) return false;
const freq1 = Array(26).fill(0), freq2 = Array(26).fill(0);
const set1 = new Set(), set2 = new Set();
for (const c of word1) {
freq1[c.charCodeAt(0) - 97]++;
set1.add(c);
}
for (const c of word2) {
freq2[c.charCodeAt(0) - 97]++;
set2.add(c);
}
if (set1.size !== set2.size || ![...set1].every(x => set2.has(x))) return false;
freq1.sort((a, b) => a - b);
freq2.sort((a, b) => a - b);
for (let i = 0; i < 26; i++) {
if (freq1[i] !== freq2[i]) return false;
}
return true;
};