键盘行

标签: 数组 哈希表 字符串

难度: Easy

给你一个字符串数组 words ,只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。

美式键盘 中:

  • 第一行由字符 "qwertyuiop" 组成。
  • 第二行由字符 "asdfghjkl" 组成。
  • 第三行由字符 "zxcvbnm" 组成。

American keyboard

 

示例 1:

输入:words = ["Hello","Alaska","Dad","Peace"]
输出:["Alaska","Dad"]

示例 2:

输入:words = ["omk"]
输出:[]

示例 3:

输入:words = ["adsdf","sfd"]
输出:["adsdf","sfd"]

 

提示:

  • 1 <= words.length <= 20
  • 1 <= words[i].length <= 100
  • words[i] 由英文字母(小写和大写字母)组成

Submission

运行时间: 24 ms

内存: 0.0 MB

class Solution:
    def findWords(self, words: List[str]) -> List[str]:
        set_h = set(['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
                    'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'])
        set_m = set(['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
                    'A','S','D','F','G','H','J','K','L'])
        set_l = set(['z', 'x', 'c', 'v', 'b', 'n', 'm',
                    'Z', 'X', 'C', 'V', 'B', 'N', 'M'])
        result = []
        for word in words:
            check_set = set()
            for c in word:
                check_set.add(c)
            if len(check_set.union(set_h)) == len(set_h) or len(check_set.union(set_m)) == len(set_m) or len(check_set.union(set_l)) == len(set_l):
                result.append(word)
                
        return result
                

Explain

该题解的思路是先将美式键盘的三行字母分别存入三个集合set_h、set_m、set_l中。然后遍历单词列表words,对于每个单词,统计其中出现的字符,存入集合check_set。最后判断check_set与set_h、set_m、set_l三个集合的并集,如果并集的大小等于set_h、set_m或set_l任一集合的大小,说明该单词的所有字母都在同一行,将其加入结果列表result中返回。

时间复杂度: O(n*m)

空间复杂度: O(m+n)

```python
class Solution:
    def findWords(self, words: List[str]) -> List[str]:
        # 初始化美式键盘三行字母的集合
        set_h = set(['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 
                    'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'])
        set_m = set(['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
                    'A','S','D','F','G','H','J','K','L'])
        set_l = set(['z', 'x', 'c', 'v', 'b', 'n', 'm',
                    'Z', 'X', 'C', 'V', 'B', 'N', 'M'])
        
        result = []
        for word in words:
            check_set = set()
            for c in word:
                check_set.add(c) # 统计单词中出现的字母
                
            # 判断单词字母是否都在同一行    
            if len(check_set.union(set_h)) == len(set_h) or \
               len(check_set.union(set_m)) == len(set_m) or \
               len(check_set.union(set_l)) == len(set_l):
                result.append(word)
                
        return result
```

Explore

该方法是准确的。当检查集合与某一行字母集合的并集大小等于该行字母集合的大小时,意味着检查集合中的所有字母都包含在这一行中。由于集合是无重复元素的,任何额外的非行字母将会使并集的大小增加,因此不可能出现包含非该行字母却使并集大小不变的情况。

使用集合的主要优势在于集合提供了更高效的查找和操作时间。集合内部基于哈希表实现,使得平均时间复杂度为O(1)的成员检查和唯一性保证。如果使用列表或元组,则成员检查的时间复杂度为O(n),这在大量操作时会较为耗时。此外,集合操作如并集、交集等也非常直接和高效,适合本题中的要求。

一种更高效的方法是直接判断单词的每个字母是否都属于同一个集合,而无需进行并集操作。可以通过检查单词中的第一个字母属于哪个集合,然后验证单词中的其余字母是否也都属于该集合。这样可以将三次并集操作简化为对单词的一次遍历,每个字母一次集合成员检查,大幅提高效率。

如果输入数据保证了只有小写或大写字母,那么确实可以简化代码。在这种情况下,可以只初始化一个小写或大写字母的集合,从而避免初始化和检查大小写两种形式的字母。这不仅简化了代码,还能减少运行时的内存占用和提高一些效率。