languages
alphabets
word frequency
linguistic analysis
language optimization

Choosing an alphabet that covers the most words?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Choosing a small alphabet that covers the most words is an optimization problem that appears in keyboard design, word games, and language learning tools. The objective is usually to pick k letters so that as many dictionary words as possible can be formed. This can be solved exactly for tiny datasets, but practical datasets typically need efficient approximations.

Problem Formulation

Given a dictionary and a target alphabet size k, define coverage as the number of words composed only of selected letters. For example, if selected letters are a, e, r, and t, words containing z are not covered.

This problem is closely related to set coverage and can become combinatorial quickly. With 26 letters and k equal to 10, brute force already has millions of combinations.

A clear formal model:

  • Universe is the word list.
  • Candidate sets are letters.
  • A word is covered when every unique letter in that word is selected.

Greedy Baseline Algorithm

A practical baseline is greedy selection. At each step, choose the letter that increases covered word count the most.

python
1from collections import Counter
2
3
4def normalize_words(words):
5    out = []
6    for w in words:
7        w = ''.join(ch for ch in w.lower() if 'a' <= ch <= 'z')
8        if w:
9            out.append(w)
10    return out
11
12
13def covered_count(words, selected):
14    s = set(selected)
15    return sum(1 for w in words if set(w).issubset(s))
16
17
18def greedy_alphabet(words, k):
19    words = normalize_words(words)
20    letters = [chr(i) for i in range(ord('a'), ord('z') + 1)]
21    selected = []
22
23    for _ in range(k):
24        best_letter = None
25        best_score = -1
26        for letter in letters:
27            if letter in selected:
28                continue
29            score = covered_count(words, selected + [letter])
30            if score > best_score:
31                best_score = score
32                best_letter = letter
33        selected.append(best_letter)
34
35    return selected, covered_count(words, selected)
36
37sample = ["tree", "tea", "rate", "zebra", "rare", "treat"]
38alphabet, score = greedy_alphabet(sample, 6)
39print(alphabet, score)

Greedy is not always optimal, but it scales and often provides strong results.

Weighted Coverage Variant

Many real applications value words differently. High frequency words should count more than rare words. You can attach weights and maximize weighted coverage.

python
1
2def weighted_covered_score(weighted_words, selected):
3    s = set(selected)
4    total = 0.0
5    for word, weight in weighted_words:
6        if set(word).issubset(s):
7            total += weight
8    return total

This shifts the objective from raw word count to practical utility.

Exact Search For Small Cases

For short alphabets or reduced candidate sets, exact search with combinations is feasible.

python
1from itertools import combinations
2
3
4def exact_best(words, k):
5    letters = sorted(set(''.join(words)))
6    best = ([], -1)
7    for combo in combinations(letters, k):
8        score = covered_count(words, combo)
9        if score > best[1]:
10            best = (list(combo), score)
11    return best

Use exact search as a benchmark for validating heuristic quality on sampled subsets.

Data Quality Matters

Results depend heavily on preprocessing. Remove punctuation, normalize case, and decide how to handle accented characters. If multilingual coverage is needed, treat each language corpus separately or include language weights.

Also decide whether repeated letters matter. For most coverage tasks, only unique letters per word matter.

Performance Notes

For large dictionaries, represent each word as a bitmask and evaluate subset checks with bit operations. This can speed coverage scoring dramatically compared with repeated set construction.

Caching intermediate coverage values can further reduce runtime in iterative search algorithms.

Common Pitfalls

  • Optimizing for total words without considering word frequency.
  • Comparing algorithms on differently preprocessed corpora.
  • Ignoring language specific characters and diacritics.
  • Assuming greedy output is globally optimal in all datasets.
  • Using brute force on full dictionaries where runtime is impractical.

Summary

  • Alphabet selection is a coverage optimization problem.
  • Greedy selection is a strong practical baseline for large inputs.
  • Weighted scoring often reflects real usage better than raw counts.
  • Exact search is useful for small benchmarks and validation.
  • Preprocessing and corpus design strongly influence final results.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms