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 for each word in words).
Return the sum of lengths of all good strings in words.
Example 1:
Input: words = ["cat","bt","hat","tree"], chars = "atach"
Output: 6Explanation: 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: 10Explanation: The strings that can be formed are "hello" and "world" so the answer is 5 + 5 = 10.
Constraints:
1 <= words.length <= 10001 <= words[i].length, chars.length <= 100words[i] and chars consist of lowercase English letters.Before attempting this problem, you should be comfortable with:
A word can be formed from chars if every character in the word appears in chars with at least the same frequency. We first count character frequencies in chars, then for each word, count its character frequencies and verify that chars has enough of each character.
count for all characters in chars.cur_word for the word.cur_word has a count less than or equal to its count in count.res.class Solution:
def countCharacters(self, words: List[str], chars: str) -> int:
count = Counter(chars)
res = 0
for w in words:
cur_word = Counter(w)
good = True
for c in cur_word:
if cur_word[c] > count[c]:
good = False
break
if good:
res += len(w)
return resWhere is the length of , is the number of words and is the average length of each word.
Instead of building the complete frequency map for each word first, we can check character availability on the fly. As we iterate through each character of a word, we increment its count in a temporary map and immediately check if it exceeds the available count in chars. This allows early termination if a word is invalid.
count for all characters in chars.cur_word.cur_word.count, mark the word as invalid and break.res.class Solution:
def countCharacters(self, words: List[str], chars: str) -> int:
count = Counter(chars)
res = 0
for w in words:
cur_word = defaultdict(int)
good = True
for c in w:
cur_word[c] += 1
if cur_word[c] > count[c]:
good = False
break
if good:
res += len(w)
return resWhere is the length of , is the number of words and is the average length of each word.
Since we only have lowercase letters, we can use a fixed-size array of 26 elements instead of a hash map. This is more cache-friendly and avoids hash function overhead. We decrement counts as we use characters and reset the array for each new word using a stored original copy.
count of size 26 and populate it with frequencies from chars.count as org for resetting.count[c - 'a'].res.count to org for the next word.class Solution:
def countCharacters(self, words: List[str], chars: str) -> int:
count = [0] * 26
for c in chars:
count[ord(c) - ord('a')] += 1
org = count[:]
res = 0
for w in words:
good = True
for c in w:
i = ord(c) - ord('a')
count[i] -= 1
if count[i] < 0:
good = False
break
if good:
res += len(w)
for i in range(26):
count[i] = org[i]
return resWhere is the length of , is the number of words and is the average length of each word.
When checking each word, you must use a fresh copy of the character counts or reset after each word. A common mistake is decrementing the original count map without restoring it, causing subsequent words to have fewer available characters than they should.
It is not enough to check if a character exists in chars; you must verify that the frequency of each character in the word does not exceed its frequency in chars. For example, "aab" cannot be formed from "ab" even though both 'a' and 'b' are present.
Sign in to join the discussion