{x}
blog image

Maximum Number of Words You Can Type

There is a malfunctioning keyboard where some letter keys do not work. All other keys on the keyboard work properly.

Given a string text of words separated by a single space (no leading or trailing spaces) and a string brokenLetters of all distinct letter keys that are broken, return the number of words in text you can fully type using this keyboard.

 

Example 1:

Input: text = "hello world", brokenLetters = "ad"
Output: 1
Explanation: We cannot type "world" because the 'd' key is broken.

Example 2:

Input: text = "leet code", brokenLetters = "lt"
Output: 1
Explanation: We cannot type "leet" because the 'l' and 't' keys are broken.

Example 3:

Input: text = "leet code", brokenLetters = "e"
Output: 0
Explanation: We cannot type either word because the 'e' key is broken.

 

Constraints:

  • 1 <= text.length <= 104
  • 0 <= brokenLetters.length <= 26
  • text consists of words separated by a single space without any leading or trailing spaces.
  • Each word only consists of lowercase English letters.
  • brokenLetters consists of distinct lowercase English letters.

Solution Explanation for Maximum Number of Words You Can Type

This problem involves determining how many words from an input string can be typed using a keyboard with certain broken keys. The solution leverages a set (or boolean array) to efficiently track broken keys and check word typability.

Approach:

  1. Represent Broken Keys: A set (Python) or boolean array (Java, C++, Go, TypeScript, Rust) is used to store the broken letters. Using a set provides O(1) lookup time for checking if a character is broken. A boolean array achieves similar efficiency.

  2. Process Words: The input text string is split into individual words using string's built-in split() method (or equivalent). Each word is then iterated through.

  3. Check Typability: For each character in a word, we check if it's present in the brokenLetters set (or boolean array). If a broken letter is found, the entire word is considered untypable, and the loop for that word breaks early.

  4. Count Typeable Words: A counter variable keeps track of the number of words that can be fully typed. If a word is completely typable (no broken letters found), the counter is incremented.

Time Complexity:

The algorithm iterates through each word in the text and each character within those words. In the worst case, this results in a time complexity of O(m*n), where 'm' is the total number of characters in text and 'n' is the average length of each word. However, the dominant factor is the number of characters processed. This can be more accurately represented as O(m). The lookup in the set/array is O(1).

Space Complexity:

The space complexity is O(k), where 'k' is the number of unique broken letters. In the worst case, all 26 lowercase letters could be broken, but it's generally much smaller. The space used by the set/array is relatively constant and doesn't scale with the input text size.

Code Examples (with slight improvements):

The provided code snippets are generally efficient, but here are a few refinements:

Python:

class Solution:
    def canBeTypedWords(self, text: str, brokenLetters: str) -> int:
        broken_set = set(brokenLetters)
        return sum(all(c not in broken_set for c in word) for word in text.split())
 

Java:

class Solution {
    public int canBeTypedWords(String text, String brokenLetters) {
        boolean[] broken = new boolean[26];
        for (char c : brokenLetters.toCharArray()) {
            broken[c - 'a'] = true;
        }
        int count = 0;
        for (String word : text.split("\\s+")) { //handles multiple spaces
            boolean typable = true;
            for (char c : word.toCharArray()) {
                if (broken[c - 'a']) {
                    typable = false;
                    break;
                }
            }
            if (typable) count++;
        }
        return count;
    }
}

C++: (using std::unordered_set for better efficiency)

#include <unordered_set>
#include <sstream>
 
class Solution {
public:
    int canBeTypedWords(string text, string brokenLetters) {
        unordered_set<char> broken(brokenLetters.begin(), brokenLetters.end());
        stringstream ss(text);
        string word;
        int count = 0;
        while (ss >> word) {
            bool typable = true;
            for (char c : word) {
                if (broken.count(c)) {
                    typable = false;
                    break;
                }
            }
            if (typable) count++;
        }
        return count;
    }
};

These improved examples maintain the same time and space complexity but offer better readability and/or handle edge cases like multiple spaces between words more robustly. The C++ example uses std::unordered_set and stringstream for potentially better performance with very large inputs, especially for the brokenLetters string. The Java example uses \\s+ to correctly handle multiple spaces between words. The Python example is already concise and efficient. The other languages' solutions would benefit from similar minor improvements.