{x}
blog image

Keyboard Row

Given an array of strings words, return the words that can be typed using letters of the alphabet on only one row of American keyboard like the image below.

Note that the strings are case-insensitive, both lowercased and uppercased of the same letter are treated as if they are at the same row.

In the American keyboard:

  • the first row consists of the characters "qwertyuiop",
  • the second row consists of the characters "asdfghjkl", and
  • the third row consists of the characters "zxcvbnm".

 

Example 1:

Input: words = ["Hello","Alaska","Dad","Peace"]

Output: ["Alaska","Dad"]

Explanation:

Both "a" and "A" are in the 2nd row of the American keyboard due to case insensitivity.

Example 2:

Input: words = ["omk"]

Output: []

Example 3:

Input: words = ["adsdf","sfd"]

Output: ["adsdf","sfd"]

 

Constraints:

  • 1 <= words.length <= 20
  • 1 <= words[i].length <= 100
  • words[i] consists of English letters (both lowercase and uppercase). 

Solution Explanation

This problem asks to filter a list of words, keeping only those that can be typed using letters from a single row of a standard QWERTY keyboard. The solution leverages the observation that letters belonging to the same row can be identified by a common numerical index.

Approach

The solutions use a mapping technique to efficiently determine which row each character belongs to. Instead of using multiple set comparisons (Solution 1), or multiple conditional checks, a single string s is used. This string's index corresponds to the character's position in the alphabet (a to z), and its value represents the keyboard row (1, 2, or 3).

The algorithm iterates through each word in the input list:

  1. Determine the row: For the first character of each word, find its index and corresponding row in the mapping string s.
  2. Check all characters: Iterate through the remaining characters of the word and ensure they all belong to the same row found in the first step.
  3. Append to result: If all characters of the word are from the same row, add the word to the result list.

Time and Space Complexity Analysis

Time Complexity: O(N*M), where N is the number of words, and M is the maximum length of a word. The algorithm iterates through each word and its characters.

Space Complexity: O(1). The space used by the s string and the result list is constant and doesn't depend on the input size. Note that in Solution 1, using sets has a small constant space overhead.

Code Explanation (Python3 - Solution 2)

This solution is concise and efficient:

class Solution:
    def findWords(self, words: List[str]) -> List[str]:
        ans = []
        s = "12210111011122000010020202"  # Mapping string: index corresponds to char, value to row
        for w in words:
            x = s[ord(w[0].lower()) - ord('a')] # get the row number for the first character.
            if all(s[ord(c.lower()) - ord('a')] == x for c in w): # Check if all chars are in same row
                ans.append(w)
        return ans

The all() function efficiently checks if all characters in the word belong to the same row. The ord() function converts characters to their ASCII values for index calculation. Lowercasing ensures case-insensitivity.

Code Explanation (Java - Solution 1)

This Java solution utilizes a similar approach but is slightly more verbose:

class Solution {
    public String[] findWords(String[] words) {
        String s = "12210111011122000010020202";
        List<String> ans = new ArrayList<>();
        for (var w : words) {
            String t = w.toLowerCase();
            char x = s.charAt(t.charAt(0) - 'a'); // Get the row for the first character
            boolean ok = true;
            for (char c : t.toCharArray()) {
                if (s.charAt(c - 'a') != x) { // Check if all chars are in the same row.
                    ok = false;
                    break;
                }
            }
            if (ok) {
                ans.add(w);
            }
        }
        return ans.toArray(new String[0]);
    }
}

The logic remains the same: find the row of the first character and then verify that all other characters belong to the same row. The use of toCharArray() iterates through the word. The result is converted from a List to a String[] for return. Similar approaches are used in other languages provided.