Hello, reader ๐๐ฝ ! Welcome to day 62 of the series on Problem Solving. Through this series, I aim to pick up at least one question everyday and share my approach for solving it.
Today, I will be picking up LeetCode's daily challenge problem: 1657. Determine if Two Strings Are Close.
๐ค Problem Statement
Two strings are considered close if one string can be attained from the other using the following operations:
Operation 1: Swap any two existing characters.
- For example,
abcde -> aecdb
- For example,
Operation 2: Transform every occurrence of one existing character into another existing character, and do the same with the other character.
- For example,
aacabb -> bbcbaa
(alla
's turn intob
's, and allb
's turn intoa
's)
- For example,
The two operations on either string can be used as many times as necessary.
Given two strings,
word1
andword2
, returntrue
ifword1
andword2
are close*, andfalse
otherwise.*E.g.:
word1 = "abc", word2 = "bca"
=>true
word1 = "cabbba", word2 = "abbccc"
=>false
๐ฌ Thought Process - Count Occurrences
There are two major cases when the strings
word1
andword1
can never be equal.When the length of two strings are different.
- E.g.:
word1 = "a"
andword2 = "aa"
.
- E.g.:
When either of the strings have characters that are not present in the other.
- E.g.:
word1 = "caaaaa", word2 = "abbccc"
- E.g.:
So, our first check will be to equate string lengths. If they are different, we can return
false
.We should also check if either of the strings have characters that are not part of the other string. This can be easily checked using a hash map or a frequency count array.
In the problem description, it is specified that the characters are going to be the smaller case letters.
Hence, we can use a boolean array of size 26 and set the flag for any character
ch
toarray[ch - 'a'] = true
.
Now, in both the arrays we are guaranteed to have same characters. But these characters could have different occurrences.
E.g.:
word1 = "cabbba", word2 = "abbccc"
In
word1
, there are 2a
, 1c
and 3b
In
word2
, there are 2b
, 1a
and 3c
Yet, it is possible to get the
word2
by using swaps and transformation operations onword1
.
Another E.g.:
word1 = "aabbcc"
andword2 = "abcbca"
.In
word1
, there are 2a
, 2c
and 2b
In
word2
, there are 2b
, 2a
and 2c
Yet, it is possible to get the
word2
by using swaps and transformation operations onword1
.
So if you see, we apply only swaps when
word1
andword2
have characters that have same occurrences and apply transformation and/ or swaps when we have characters with different occurrences.But look at this example:
word1 = "aaabcc"
andword2 = "aaaabc"
Both the words have:
Equal length
All characters in
word1
appearing inword
and vice versa
Yet, it is impossible to obtain
word2
fromword1
.Even, if we try to transform
a
tob
orb
toc
, and do a series of swaps, we will not be able to achieveword2
.This is because of difference frequencies:
In
word1
, there are 3a
, 1b
and 2c
In
word2
, there are 4a
, 1b
and 1c
Unless there was one letter in word1 that occurred 4 times and another letter (apart from
b
), that occurred once,word1
can never be attained.
Hence, this is where the next clue is. If the frequencies (need not be the exact same character) of both words are different,
word2
can never be attained fromword1
.In other words all the characters in
word1
need not have strictly the same frequency of the characters inword2
.But the frequency count in itself should have occurred in
word1
for any character if it occurred forword2
.So if there were 2 characters that had frequency 4 in
word2
, there must be exactly 2 characters (need not be same) inword1
that has frequency 4.Hence we can use two arrays of size 26 of integer type to keep count of number of characters in both the strings.
Then we can sort the frequency array for both words and use a single loop to traverse and check if the indices at both array contain the same value.
E.g.:
word1 = "aabbcc"
andword2 = "abcbca"
Their frequency array would be as follows:
word1Count = [2, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
word2Count = [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
After sorting:
word1Count = [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
word2Count = [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
At every index, both the count arrays have the same value. If we find any mismatch, we return false immediately.
๐ฉ๐ฝโ๐ป Solution - One pass + Count
- Below is the code for the approach using one pass iteration and count.
class Solution {
public boolean closeStrings(String word1, String word2) {
if(word1.length() != word2.length()) return false;
int n = word1.length();
int[] frequencyWordOne = new int[26];
int[] frequencyWordTwo = new int[26];
for(int i = 0; i<n; i++) {
char ch = word1.charAt(i);
frequencyWordOne[ch - 'a']++;
}
for(int i = 0; i<n; i++) {
char ch = word2.charAt(i);
if(frequencyWordOne[ch - 'a'] == 0) {
return false;
}
frequencyWordTwo[ch - 'a']++;
}
Arrays.sort(frequencyWordOne);
Arrays.sort(frequencyWordTwo);
for(int i = 0; i<26; i++) {
if(frequencyWordOne[i] != frequencyWordTwo[i]) {
return false;
}
}
return true;
}
}
Time Complexity: O(n)
- n = length of string
- Note: since the array sizes are constant (26), the sorting
is basically done on a constant array with (26 * log 26)
Space Complexity: O(1)
- Note: The arrays are of fixed size 26 and do not scale as
input size grows
- You can find the link to the GitHub repo for this question here: 1657. Determine if Two Strings Are Close.
Conclusion
That's a wrap for today's problem. If you liked my explanation then please do drop a like/ comment. Also, please correct me if I've made any mistakes or if you want me to improve something!
Thank you for reading!