2135. Count Words Obtained After Adding a Letter
Description
You are given two 0-indexed arrays of strings startWords
and targetWords
. Each string consists of lowercase English letters only.
For each string in targetWords
, check if it is possible to choose a string from startWords
and perform a conversion operation on it to be equal to that from targetWords
.
The conversion operation is described in the following two steps:
- Append any lowercase letter that is not present in the string to its end.
<ul> <li>For example, if the string is <code>"abc"</code>, the letters <code>'d'</code>, <code>'e'</code>, or <code>'y'</code> can be added to it, but not <code>'a'</code>. If <code>'d'</code> is added, the resulting string will be <code>"abcd"</code>.</li> </ul> </li> <li><strong>Rearrange</strong> the letters of the new string in <strong>any</strong> arbitrary order. <ul> <li>For example, <code>"abcd"</code> can be rearranged to <code>"acbd"</code>, <code>"bacd"</code>, <code>"cbda"</code>, and so on. Note that it can also be rearranged to <code>"abcd"</code> itself.</li> </ul> </li>
Return the number of strings in targetWords
that can be obtained by performing the operations on any string of startWords
.
Note that you will only be verifying if the string in targetWords
can be obtained from a string in startWords
by performing the operations. The strings in startWords
do not actually change during this process.
Example 1:
Input: startWords = ["ant","act","tack"], targetWords = ["tack","act","acti"] Output: 2 Explanation: - In order to form targetWords[0] = "tack", we use startWords[1] = "act", append 'k' to it, and rearrange "actk" to "tack". - There is no string in startWords that can be used to obtain targetWords[1] = "act". Note that "act" does exist in startWords, but we must append one letter to the string before rearranging it. - In order to form targetWords[2] = "acti", we use startWords[1] = "act", append 'i' to it, and rearrange "acti" to "acti" itself.
Example 2:
Input: startWords = ["ab","a"], targetWords = ["abc","abcd"] Output: 1 Explanation: - In order to form targetWords[0] = "abc", we use startWords[0] = "ab", add 'c' to it, and rearrange it to "abc". - There is no string in startWords that can be used to obtain targetWords[1] = "abcd".
Constraints:
1 <= startWords.length, targetWords.length <= 5 * 104
1 <= startWords[i].length, targetWords[j].length <= 26
- Each string of
startWords
andtargetWords
consists of lowercase English letters only. - No letter occurs more than once in any string of
startWords
ortargetWords
.
Solutions
Solution 1: Hash Table + Bit Manipulation
We notice that the given strings only contain lowercase letters, and each letter in a string appears at most once. Therefore, we can represent a string with a binary number of length $26$, where the $i$-th bit being $1$ indicates that the string contains the $i$-th lowercase letter, and $0$ indicates the absence of the $i$-th lowercase letter.
We can convert each string in the array $\textit{startWords}$ into a binary number and store these binary numbers in a set $\textit{s}$. For each string in the array $\textit{targetWords}$, we first convert it into a binary number, then enumerate each letter in this string, remove this letter from the binary number, and check if there exists a binary number in the set $\textit{s}$ such that the XOR result of this binary number with the removed letter's binary number is in the set $\textit{s}$. If such a binary number exists, then this string can be obtained by performing a transformation operation on some string in $\textit{startWords}$, and we increment the answer by one. Then, we skip this string and continue processing the next string.
The time complexity is $O(n \times |\Sigma|)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string array $\textit{targetWords}$, and $|\Sigma|$ is the size of the character set in the string, which is $26$ in this problem.
Python3
class Solution:
def wordCount(self, startWords: List[str], targetWords: List[str]) -> int:
s = {sum(1 << (ord(c) - 97) for c in w) for w in startWords}
ans = 0
for w in targetWords:
x = sum(1 << (ord(c) - 97) for c in w)
for c in w:
if x ^ (1 << (ord(c) - 97)) in s:
ans += 1
break
return ans
Java
class Solution {
public int wordCount(String[] startWords, String[] targetWords) {
Set<Integer> s = new HashSet<>();
for (var w : startWords) {
int x = 0;
for (var c : w.toCharArray()) {
x |= 1 << (c - 'a');
}
s.add(x);
}
int ans = 0;
for (var w : targetWords) {
int x = 0;
for (var c : w.toCharArray()) {
x |= 1 << (c - 'a');
}
for (var c : w.toCharArray()) {
if (s.contains(x ^ (1 << (c - 'a')))) {
++ans;
break;
}
}
}
return ans;
}
}
C++
class Solution {
public:
int wordCount(vector<string>& startWords, vector<string>& targetWords) {
unordered_set<int> s;
for (auto& w : startWords) {
int x = 0;
for (char c : w) {
x |= 1 << (c - 'a');
}
s.insert(x);
}
int ans = 0;
for (auto& w : targetWords) {
int x = 0;
for (char c : w) {
x |= 1 << (c - 'a');
}
for (char c : w) {
if (s.contains(x ^ (1 << (c - 'a')))) {
++ans;
break;
}
}
}
return ans;
}
};
Go
func wordCount(startWords []string, targetWords []string) (ans int) {
s := map[int]bool{}
for _, w := range startWords {
x := 0
for _, c := range w {
x |= 1 << (c - 'a')
}
s[x] = true
}
for _, w := range targetWords {
x := 0
for _, c := range w {
x |= 1 << (c - 'a')
}
for _, c := range w {
if s[x^(1<<(c-'a'))] {
ans++
break
}
}
}
return
}
TypeScript
function wordCount(startWords: string[], targetWords: string[]): number {
const s = new Set<number>();
for (const w of startWords) {
let x = 0;
for (const c of w) {
x ^= 1 << (c.charCodeAt(0) - 97);
}
s.add(x);
}
let ans = 0;
for (const w of targetWords) {
let x = 0;
for (const c of w) {
x ^= 1 << (c.charCodeAt(0) - 97);
}
for (const c of w) {
if (s.has(x ^ (1 << (c.charCodeAt(0) - 97)))) {
++ans;
break;
}
}
}
return ans;
}