3941. Password Strength
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.
How We Pick the Algorithm
Why Hash Table / Counting?
This problem maps to Hash Table / Counting through a short path in the full flowchart.
Using a hash map for constant-time frequency counting enables the solution.
Open in FlowchartIntuition
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'), add1point. - If the character is an uppercase letter (
'A'to'Z'), add2points. - If the character is a digit (
'0'to'9'), add3points. - If the character is a special character (from the set
"!@#$"), add5points.
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:
| Character | Action | Set 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:
| Character | Classification | Check that matches | Points added | Running ans |
|---|---|---|---|---|
'a' | lowercase letter | ch.islower() | 1 | 1 |
'A' | uppercase letter | ch.isupper() | 2 | 3 |
'1' | digit | ch.isdigit() | 3 | 6 |
'!' | special character ("!@#$") | else branch | 5 | 11 |
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
251class 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}
321class 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};
311/**
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}
40Time and Space Complexity
-
Time Complexity:
O(n), wherenis the length of the input stringpassword. Constructing the setst = set(password)requires iterating over allncharacters, takingO(n)time. The subsequentforloop iterates over the distinct characters in the set, which is at mostn, so it contributesO(m)wherem ≤ n. The character checks (islower,isupper,isdigit) inside the loop are eachO(1). Therefore, the overall time complexity is dominated by the set construction, givingO(n). -
Space Complexity:
O(m), wheremis the number of distinct characters in the input string. The setststores only the unique characters frompassword, so its size ism. In the worst case, all characters are distinct andm = n, but in general the space used isO(m). The variableansand the loop variablechuse 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()returnsTrue(superscript two), but it isn't'0'–'9'.'ñ'.islower()returnsTrue, but it isn't an ASCII lowercase letter.'٤'.isdigit()(Arabic-Indic digit) also returnsTrue.
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 RoadmapWhat'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
271private 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}
301const 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}
30Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity describes how the time needed
Want a Structured Path to Master System Design Too? Don’t Miss This!