string
programming
unique characters
algorithm
coding

Easiest way of checking if a string consists of unique letters?

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

Checking whether a string consists of unique letters sounds like a toy problem, but the right answer depends on what your application means by "same letter." For code-kata input, a set-based check is usually enough. For user-facing text, you may also need to think about case, punctuation, and Unicode normalization before deciding whether the characters are truly unique.

The Simple Set-Based Solution

If each character should be treated literally, the easiest solution is to compare the string length with the number of distinct characters.

python
1def has_unique_characters(text: str) -> bool:
2    return len(text) == len(set(text))
3
4
5print(has_unique_characters("lamp"))    # True
6print(has_unique_characters("letter"))  # False

This is the best default for machine-oriented input where every character matters exactly as it appears. The algorithm runs in linear time and the code is short enough that most readers understand it immediately.

Decide Whether Case Differences Count

Many real requirements do not want A and a to count as different letters. In that case, normalize the string before building the set. In Python, casefold() is often better than lower() because it is designed for broader Unicode-aware case normalization.

python
1def has_unique_letters_case_insensitive(text: str) -> bool:
2    normalized = text.casefold()
3    return len(normalized) == len(set(normalized))
4
5
6print(has_unique_letters_case_insensitive("Abc"))  # True
7print(has_unique_letters_case_insensitive("Aab"))  # False

The algorithm is still linear. The important change is not performance. It is that the code now matches a clearer definition of letter equality.

Filter to Letters Only When That Is the Rule

Sometimes the input may contain spaces, digits, or punctuation, but the requirement is about letters only. That should be expressed directly in the implementation rather than assumed by the caller.

python
1def has_unique_alpha_only(text: str) -> bool:
2    letters = [ch.casefold() for ch in text if ch.isalpha()]
3    return len(letters) == len(set(letters))
4
5
6print(has_unique_alpha_only("New York"))   # False
7print(has_unique_alpha_only("lamp!"))      # True

This version treats non-letter characters as irrelevant. That is a different business rule from the literal character version, so it should usually have its own function name and tests.

Unicode Can Break Naive Checks

User-facing text introduces a subtle problem: two strings can look identical but be encoded differently. Some accented letters may appear as a single code point or as a base letter plus a combining mark. If you skip normalization, uniqueness checks can behave inconsistently.

python
1import unicodedata
2
3
4def normalize_text(text: str) -> str:
5    return unicodedata.normalize("NFC", text).casefold()
6
7
8def has_unique_normalized_letters(text: str) -> bool:
9    normalized = normalize_text(text)
10    letters = [ch for ch in normalized if ch.isalpha()]
11    return len(letters) == len(set(letters))

This matters whenever input can come from browsers, mobile keyboards, copied text, or imported files. If the application is user-facing, Unicode rules are part of correctness, not an optional enhancement.

Bitmasks Are Fine for Restricted Alphabets

Interview problems often assume lowercase English letters only. In that case, a bitmask approach is compact and fast.

python
1def has_unique_lowercase_ascii(text: str) -> bool:
2    mask = 0
3
4    for ch in text:
5        index = ord(ch) - ord("a")
6        if index < 0 or index > 25:
7            raise ValueError("expected lowercase letters a-z")
8
9        bit = 1 << index
10        if mask & bit:
11            return False
12        mask |= bit
13
14    return True

This is efficient, but it is only easy if the input contract is truly limited. The moment uppercase letters or non-English characters enter the picture, the bitmask version stops being the simplest correct solution.

Test the Rule, Not Just the Code

A helper this small still deserves tests because the tricky part is often the requirement rather than the implementation. At minimum, test empty input, repeated letters, mixed case, and a Unicode example if the function is intended for real text.

That gives future maintainers a written definition of what "unique" means in your system. Without tests, people tend to change case handling or filtering behavior casually and discover later that they changed the business rule.

Common Pitfalls

The biggest mistake is coding before defining whether case matters. Another is assuming visually identical Unicode text is encoded identically. Teams also overuse bitmask tricks on unrestricted input, or they forget to specify whether spaces and punctuation should count.

Summary

  • A set-based length comparison is the easiest reliable default.
  • Normalize case before checking uniqueness if A and a should be treated the same.
  • Filter to alphabetic characters only when the requirement explicitly says so.
  • Unicode normalization matters for real user-facing text.
  • Bitmask solutions are useful for fixed alphabets, not for general text handling.

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

All Rights Reserved.