Facebook Pixel

3941. Password Strength

MediumHash TableString
LeetCode ↗

Problem Description

You are given a string password.

The strength of the password is calculated by looking at the distinct characters it contains and adding up points based on the type of each character:

  • 1 point for each distinct lowercase letter ('a' to 'z').
  • 2 points for each distinct uppercase letter ('A' to 'Z').
  • 3 points for each distinct digit ('0' to '9').
  • 5 points for each distinct special character from the set "!@#$".

The key detail is that each character contributes at most once to the total score. Even if a character appears multiple times in the string, it is only counted a single time.

Your task is to return an integer representing the total strength of the given password.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Hash Table / Counting?

This problem maps to Hash Table / Counting through a short path in the full flowchart.

Linkedlist?noFastlookup orcounting?yesHash Table /Counting

Using a hash map for constant-time frequency counting enables the solution.

Open in Flowchart

Intuition

The problem tells us that each character should only be counted once, no matter how many times it appears in the string. This naturally points us toward removing duplicates first.

A simple way to keep only the distinct characters is to put every character of password into a hash set. A set automatically discards duplicates, so after this step we are left with exactly one copy of each unique character.

Once we have the distinct characters, the rest is straightforward: we just need to classify each one and add the matching number of points. By checking the category in order — lowercase, uppercase, digit, and finally the special characters "!@#$" — we can map each character to its score (1, 2, 3, or 5) and accumulate the total.

This way we handle the "at most once" rule by deduplicating up front, then turn the scoring rules into a single pass over the unique characters.

Solution Approach

Solution 1: Hash Table

We store each character in the input string in a hash set st, so we can quickly ensure each distinct character is counted only once.

Then, we iterate through each character in st and compute the password strength according to the rules:

  • If the character is a lowercase letter ('a' to 'z'), add 1 point.
  • If the character is an uppercase letter ('A' to 'Z'), add 2 points.
  • If the character is a digit ('0' to '9'), add 3 points.
  • If the character is a special character (from the set "!@#$"), add 5 points.

Finally, return the computed password strength stored in ans.

In the implementation, we use Python's built-in string methods to classify each character: ch.islower() checks for lowercase letters, ch.isupper() checks for uppercase letters, and ch.isdigit() checks for digits. Since the only remaining possibility is a special character from "!@#$", the final else branch handles it directly by adding 5 points.

The time complexity is O(n), where n is the length of the string password, since we scan the string once to build the set and once more over its distinct elements. The space complexity is O(|\Sigma|), where |\Sigma| is the size of the character set, because the hash set holds at most one copy of each distinct character.

Example Walkthrough

Let's trace through the solution approach using a small example: password = "aA1!a".

Step 1: Build the hash set to remove duplicates

We scan each character of "aA1!a" and insert it into a set st:

CharacterActionSet st after insertion
'a'new, add it{'a'}
'A'new, add it{'a', 'A'}
'1'new, add it{'a', 'A', '1'}
'!'new, add it{'a', 'A', '1', '!'}
'a'already present, skip{'a', 'A', '1', '!'}

After this pass, the duplicate 'a' has been discarded, and we are left with 4 distinct characters: 'a', 'A', '1', '!'.

Step 2: Classify each distinct character and accumulate points

We start with ans = 0 and iterate over the set, applying the scoring rules in order — lowercase, uppercase, digit, then special character:

CharacterClassificationCheck that matchesPoints addedRunning ans
'a'lowercase letterch.islower()11
'A'uppercase letterch.isupper()23
'1'digitch.isdigit()36
'!'special character ("!@#$")else branch511

Step 3: Return the result

The final total strength is ans = 11.

Notice how the second 'a' in the original string contributed nothing extra — because the set already deduplicated it, the "at most once" rule was handled automatically before scoring even began. The remaining work was simply mapping each unique character to its category score (1, 2, 3, or 5) and summing them up.

Solution Implementation

1class Solution:
2    def passwordStrength(self, password: str) -> int:
3        # Collect the unique characters from the password.
4        # Duplicate characters only count once toward the strength.
5        unique_chars = set(password)
6
7        # Accumulate the total strength score.
8        strength = 0
9
10        for char in unique_chars:
11            if char.islower():
12                # Lowercase letters contribute 1 point each.
13                strength += 1
14            elif char.isupper():
15                # Uppercase letters contribute 2 points each.
16                strength += 2
17            elif char.isdigit():
18                # Digits contribute 3 points each.
19                strength += 3
20            else:
21                # Any other character (e.g., symbols) contributes 5 points each.
22                strength += 5
23
24        return strength
25
1class Solution {
2    public int passwordStrength(String password) {
3        // Collect distinct characters from the password into a set,
4        // so each unique character is counted only once.
5        Set<Character> uniqueChars = password.chars()
6                .mapToObj(c -> (char) c)
7                .collect(Collectors.toSet());
8
9        // Accumulate the total strength score.
10        int strength = 0;
11
12        // Evaluate each distinct character and add its weighted score.
13        for (char ch : uniqueChars) {
14            if (Character.isLowerCase(ch)) {
15                // Lowercase letters contribute 1 point.
16                strength += 1;
17            } else if (Character.isUpperCase(ch)) {
18                // Uppercase letters contribute 2 points.
19                strength += 2;
20            } else if (Character.isDigit(ch)) {
21                // Digits contribute 3 points.
22                strength += 3;
23            } else {
24                // Any other character (e.g., special symbols) contributes 5 points.
25                strength += 5;
26            }
27        }
28
29        return strength;
30    }
31}
32
1class Solution {
2public:
3    int passwordStrength(string password) {
4        // Use a set to keep only the distinct characters of the password,
5        // since each unique character type contributes to the strength once.
6        unordered_set<char> uniqueChars(password.begin(), password.end());
7
8        // Accumulator for the total strength score.
9        int strength = 0;
10
11        // Evaluate each distinct character and add its weighted value.
12        for (char currentChar : uniqueChars) {
13            if (islower(currentChar)) {
14                // Lowercase letter contributes 1 point.
15                strength += 1;
16            } else if (isupper(currentChar)) {
17                // Uppercase letter contributes 2 points.
18                strength += 2;
19            } else if (isdigit(currentChar)) {
20                // Digit contributes 3 points.
21                strength += 3;
22            } else {
23                // Any other character (e.g., special symbol) contributes 5 points.
24                strength += 5;
25            }
26        }
27
28        return strength;
29    }
30};
31
1/**
2 * Calculate the strength score of a given password.
3 *
4 * The score is computed over the set of distinct characters in the password.
5 * Each unique character contributes a weight based on its category:
6 *   - lowercase letter (a-z): +1
7 *   - uppercase letter (A-Z): +2
8 *   - digit (0-9):            +3
9 *   - any other character:    +5
10 *
11 * @param password - The input password string.
12 * @returns The total strength score.
13 */
14function passwordStrength(password: string): number {
15    // Collect the distinct characters so each character is counted only once.
16    const uniqueChars: Set<string> = new Set(password);
17
18    // Accumulator for the total strength score.
19    let score = 0;
20
21    // Evaluate every distinct character and add its corresponding weight.
22    for (const char of uniqueChars) {
23        if (/[a-z]/u.test(char)) {
24            // Lowercase letter contributes 1 point.
25            score += 1;
26        } else if (/[A-Z]/u.test(char)) {
27            // Uppercase letter contributes 2 points.
28            score += 2;
29        } else if (/\d/u.test(char)) {
30            // Digit contributes 3 points.
31            score += 3;
32        } else {
33            // Any other character (symbols, etc.) contributes 5 points.
34            score += 5;
35        }
36    }
37
38    return score;
39}
40

Time and Space Complexity

  • Time Complexity: O(n), where n is the length of the input string password. Constructing the set st = set(password) requires iterating over all n characters, taking O(n) time. The subsequent for loop iterates over the distinct characters in the set, which is at most n, so it contributes O(m) where m ≤ n. The character checks (islower, isupper, isdigit) inside the loop are each O(1). Therefore, the overall time complexity is dominated by the set construction, giving O(n).

  • Space Complexity: O(m), where m is the number of distinct characters in the input string. The set st stores only the unique characters from password, so its size is m. In the worst case, all characters are distinct and m = n, but in general the space used is O(m). The variable ans and the loop variable ch use only constant extra space.

Pattern Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Forgetting to Deduplicate Characters

The most common mistake is iterating directly over the password string instead of its distinct characters. This causes characters that appear multiple times to be scored repeatedly, inflating the result.

# WRONG: counts duplicates multiple times
strength = 0
for char in password:          # iterates every occurrence
    if char.islower():
        strength += 1
    # ...

For example, "aa" would yield 2 instead of the correct 1. The fix is to build a set first so each character is processed exactly once:

for char in set(password):     # iterates distinct characters only
    ...

Pitfall 2: Misclassifying Characters Through Loose else Handling

The solution relies on the else branch to catch special characters from "!@#$". This works only if the problem guarantees that the password contains nothing but lowercase, uppercase, digits, and these four symbols. If an unexpected character slips in (e.g., a space, '%', or a Unicode letter), it will silently be awarded 5 points, masking the bug.

A more defensive approach explicitly checks membership in the special set:

SPECIAL = set("!@#$")

for char in set(password):
    if char.islower():
        strength += 1
    elif char.isupper():
        strength += 2
    elif char.isdigit():
        strength += 3
    elif char in SPECIAL:
        strength += 5
    # else: unexpected character — handle or raise as needed

Pitfall 3: Relying on Python String Methods for Non-ASCII Input

str.islower(), str.isupper(), and str.isdigit() are Unicode-aware, not ASCII-restricted. They return True for many characters outside 'a''z', 'A''Z', and '0''9':

  • '²'.isdigit() returns True (superscript two), but it isn't '0''9'.
  • 'ñ'.islower() returns True, but it isn't an ASCII lowercase letter.
  • '٤'.isdigit() (Arabic-Indic digit) also returns True.

If the input domain is strictly ASCII as the problem states, this is harmless. To be fully safe, compare against explicit ranges:

for char in set(password):
    if 'a' <= char <= 'z':
        strength += 1
    elif 'A' <= char <= 'Z':
        strength += 2
    elif '0' <= char <= '9':
        strength += 3
    elif char in "!@#$":
        strength += 5

This eliminates ambiguity and guarantees correct scoring regardless of input.

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

What's the output of running the following function using input 56?

1KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13    def dfs(path, res):
14        if len(path) == len(digits):
15            res.append(''.join(path))
16            return
17
18        next_number = digits[len(path)]
19        for letter in KEYBOARD[next_number]:
20            path.append(letter)
21            dfs(path, res)
22            path.pop()
23
24    res = []
25    dfs([], res)
26    return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2    '2', "abc".toCharArray(),
3    '3', "def".toCharArray(),
4    '4', "ghi".toCharArray(),
5    '5', "jkl".toCharArray(),
6    '6', "mno".toCharArray(),
7    '7', "pqrs".toCharArray(),
8    '8', "tuv".toCharArray(),
9    '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13    List<String> res = new ArrayList<>();
14    dfs(new StringBuilder(), res, digits.toCharArray());
15    return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19    if (path.length() == digits.length) {
20        res.add(path.toString());
21        return;
22    }
23    char next_digit = digits[path.length()];
24    for (char letter : KEYBOARD.get(next_digit)) {
25        path.append(letter);
26        dfs(path, res, digits);
27        path.deleteCharAt(path.length() - 1);
28    }
29}
30
1const KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13    let res = [];
14    dfs(digits, [], res);
15    return res;
16}
17
18function dfs(digits, path, res) {
19    if (path.length === digits.length) {
20        res.push(path.join(''));
21        return;
22    }
23    let next_number = digits.charAt(path.length);
24    for (let letter of KEYBOARD[next_number]) {
25        path.push(letter);
26        dfs(digits, path, res);
27        path.pop();
28    }
29}
30

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More