{x}
blog image

Find Words That Can Be Formed by Characters

You are given an array of strings words and a string chars.

A string is good if it can be formed by characters from chars (each character can only be used once).

Return the sum of lengths of all good strings in words.

 

Example 1:

Input: words = ["cat","bt","hat","tree"], chars = "atach"
Output: 6
Explanation: The strings that can be formed are "cat" and "hat" so the answer is 3 + 3 = 6.

Example 2:

Input: words = ["hello","world","leetcode"], chars = "welldonehoneyr"
Output: 10
Explanation: The strings that can be formed are "hello" and "world" so the answer is 5 + 5 = 10.

 

Constraints:

  • 1 <= words.length <= 1000
  • 1 <= words[i].length, chars.length <= 100
  • words[i] and chars consist of lowercase English letters.

Solution Explanation:

This problem asks us to find the sum of lengths of all words in a given array that can be formed using the characters from another given string, with each character used at most once. The optimal approach uses character counting to efficiently determine if a word is "good".

Approach:

  1. Character Counting in chars: First, we count the occurrences of each character in the string chars. We can use a hash map (dictionary in Python, map in C++, etc.) or an array of size 26 (since we only deal with lowercase English letters) to store these counts.

  2. Iterating Through Words: We then iterate through each word in the words array.

  3. Character Counting in word: For each word, we count the occurrences of its characters, again using a hash map or array.

  4. Comparison: We compare the character counts of the current word with the counts from chars. If, for every character in the word, its count in the word is less than or equal to its count in chars, then the word is "good," and we add its length to the total sum.

  5. Return Total Length: Finally, we return the accumulated sum of lengths of all "good" words.

Time and Space Complexity Analysis:

  • Time Complexity: O(L), where L is the total number of characters in all words in the input array words plus the length of chars. This is because we iterate through chars once and then through each character of each word in words. The character counting within each word is also linear in the length of the word.

  • Space Complexity: O(1). We use a fixed-size array (or hash map, but the size remains constant at 26, representing the English alphabet) to store character counts. The space used is independent of the input size, making the space complexity constant.

Code Implementation in Multiple Languages:

The following code examples demonstrate the solution in several languages. They all follow the same algorithmic approach. Note that the choice between an array (for direct character indexing) or a hash map (for more flexibility) is largely a stylistic one in this specific problem. The array approach is slightly more efficient.

Python:

from collections import Counter
 
class Solution:
    def countCharacters(self, words: List[str], chars: str) -> int:
        char_counts = Counter(chars)
        total_length = 0
        for word in words:
            word_counts = Counter(word)
            is_good = True
            for char, count in word_counts.items():
                if char_counts[char] < count:
                    is_good = False
                    break
            if is_good:
                total_length += len(word)
        return total_length

Java:

class Solution {
    public int countCharacters(String[] words, String chars) {
        int[] charCounts = new int[26];
        for (char c : chars.toCharArray()) {
            charCounts[c - 'a']++;
        }
        int totalLength = 0;
        for (String word : words) {
            int[] wordCounts = new int[26];
            boolean isGood = true;
            for (char c : word.toCharArray()) {
                wordCounts[c - 'a']++;
            }
            for (int i = 0; i < 26; i++) {
                if (wordCounts[i] > charCounts[i]) {
                    isGood = false;
                    break;
                }
            }
            if (isGood) {
                totalLength += word.length();
            }
        }
        return totalLength;
    }
}

C++:

class Solution {
public:
    int countCharacters(vector<string>& words, string chars) {
        vector<int> charCounts(26, 0);
        for (char c : chars) {
            charCounts[c - 'a']++;
        }
        int totalLength = 0;
        for (const string& word : words) {
            vector<int> wordCounts(26, 0);
            bool isGood = true;
            for (char c : word) {
                wordCounts[c - 'a']++;
            }
            for (int i = 0; i < 26; i++) {
                if (wordCounts[i] > charCounts[i]) {
                    isGood = false;
                    break;
                }
            }
            if (isGood) {
                totalLength += word.length();
            }
        }
        return totalLength;
    }
};

The other languages (Go, TypeScript, PHP) would follow a very similar structure, using their respective data structures for character counting. The core algorithmic idea remains consistent across all implementations.