拼写单词

来源 leetcode 1160.拼写单词

思路

遇到字符串仅包含小写(或者大写)英文字母的题,都可以试着考虑构造长度为 26 的数组。这样,数组每个位置分别代表一个字母,统计出字母出现的次数,方便后面问题的解决。

本题中,既要统计“字母表”中字母出现的次数,也要统计单词中字母出现的次数。如果字母表中字母出现的次数大于等于单词中每种字母出现的次数,那么这个单词就可以由字母表拼写出来。

以字母表 “atach” 和 词汇 “cat” 为例,整个过程图示如下:

my ugly code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution(object):
    def countCharacters(self, words, chars):
        """
        :type words: List[str]
        :type chars: str
        :rtype: int
        """
        res = []
        for word in words:
            if self.check_word_in_chars(word, chars):
                res.append(word)
        count = 0
        for word in res:
            count += len(word)
        return count


    def check_word_in_chars(self, word, chars):
        wordDict = {}
        charsDict = {}

        for wordChar in word:
            if wordDict.get(wordChar) == None:
                wordDict[wordChar] = 1
            else:
                wordDict[wordChar] += 1


        for char in chars:
            if charsDict.get(char) == None:
                charsDict[char] = 1
            else:
                charsDict[char] += 1

        # 检查字母表里面字母出现的次数是不是大于词汇中字母出现的次数
        flag = False
        wordLength = len(wordDict)
        count = 0
        for wchar in wordDict:
            if charsDict.get(wchar) and wordDict.get(wchar):
                if charsDict[wchar] >= wordDict[wchar]:
                    count += 1
        if count == wordLength:
            flag = True
        return flag

明显上述代码效率就不高,经历了循环嵌套,而且相关实现代码重复啰嗦, 甚至会达到O(n^2)的复杂度;

高手思路赏析

解题思路

​ 显然,对于一个单词 word,只要其中的每个字母的数量都不大于 chars 中对应的字母的数量,那么就可以用 chars 中的字母拼写出 word。所以我们只需要用一个哈希表存储 chars 中每个字母的数量,再用一个哈希表存储 word 中每个字母的数量,最后将这两个哈希表的键值对逐一进行比较即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution:
    def countCharacters(self, words: List[str], chars: str) -> int:
        chars_cnt = collections.Counter(chars)
        ans = 0
        for word in words:
            word_cnt = collections.Counter(word)
            for c in word_cnt:
                if chars_cnt[c] < word_cnt[c]:
                    break
            else:
                ans += len(word)
        return ans

复杂度分析

  • 时间复杂度:O(n),其中 n 为所有字符串的长度和。我们需要遍历每个字符串,包括 chars 以及数组 words 中的每个单词。

  • 空间复杂度:O(S),其中 S为字符集大小,在本题中 S的值为 26(所有字符串仅包含小写字母)。程序运行过程中,最多同时存在两个哈希表,使用的空间均不超过字符集大小 S,因此空间复杂度为 O(S)。