A password is considered strong if the below conditions are all met:
6
characters and at most 20
characters."Baaaabb0"
is weak, but "Baaba0"
is strong).Given a string password
, return the minimum number of steps required to make password
strong. if password
is already strong, return 0
.
In one step, you can:
password
,password
or,password
with another character.Examples:
Example 1: Input: password = "a" Output: 5
Example 2: Input: password = "aA1" Output: 3
Example 3: Input: password = "1337C0d3" Output: 0
What is the most efficient way to solve this problem?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method for the password checker is like trying every possible password combination. We generate passwords systematically, and for each one, check if it meets all the strength requirements. If it doesn't, we move to the next password until we find the shortest one that satisfies all criteria.
Here's how the algorithm would work step-by-step:
def strong_password_checker_brute_force(password):
minimum_length = 6
maximum_length = 20
# We start from a minimum possible password length and try all
for password_length in range(1, maximum_length + 1):
possible_characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-+"
# Recursively generate every possible password of current length
def generate_passwords(current_length, current_password):
if current_length == 0:
if is_valid_password(current_password):
return current_password
else:
return None
for character in possible_characters:
result = generate_passwords(current_length - 1, character + current_password)
if result:
return result
return None
shortest_valid_password = generate_passwords(password_length, "")
# If we found a valid password, we can stop early.
if shortest_valid_password:
if len(password) < minimum_length:
return minimum_length - len(password)
else:
return len(shortest_valid_password) - len(password)
# Helper function to determine password validity
def is_valid_password(password_to_check):
has_lowercase = any(character.islower() for character in password_to_check)
has_uppercase = any(character.isupper() for character in password_to_check)
has_digit = any(character.isdigit() for character in password_to_check)
no_repeating = all(password_to_check[i] != password_to_check[i+1] for i in range(len(password_to_check) - 1)) if len(password_to_check) > 1 else True
# Check that the password length meets requirements
if len(password_to_check) < minimum_length or len(password_to_check) > maximum_length:
return False
# Password must meet these 3 character variety requirements
if not (has_lowercase and has_uppercase and has_digit):
return False
# Password must not have repeating characters
if not no_repeating:
return False
return True
return 0
The goal is to make a password strong by making the fewest changes possible. The strategy is to identify what the password is missing (length, character types) and then fix the biggest problems first.
Here's how the algorithm would work step-by-step:
def strong_password_checker(password):
password_length = len(password)
changes_needed = 0
missing_lower = not any(character.islower() for character in password)
missing_upper = not any(character.isupper() for character in password)
missing_digit = not any(character.isdigit() for character in password)
missing_count = missing_lower + missing_upper + missing_digit
if password_length < 6:
changes_needed += max(missing_count, 6 - password_length)
elif password_length > 20:
difference = password_length - 20
changes_needed += difference
# Prioritize removing longer repeating sequences
repeating_groups = []
index = 0
while index < password_length:
length = 1
while index + length < password_length and password[index + length] == password[index]:
length += 1
if length >= 3:
repeating_groups.append((length, index))
index += length
repeating_groups.sort(reverse=True)
reduction_map = [0] * password_length
for length, index in repeating_groups:
if difference <= 0:
break
reduction_size = min(length // 3, difference)
for i in range(index, index + reduction_size * 3, 3):
reduction_map[i] = 1
difference -= reduction_size
missing_count = max(0, missing_count - sum(reduction_map))
changes_needed += missing_count
else:
# Password length is within acceptable range
index = 0
repeating_count = 0
while index < password_length:
length = 1
while index + length < password_length and password[index + length] == password[index]:
length += 1
if length >= 3:
repeating_count += length // 3
index += length
# Replacing characters for missing types
changes_needed += max(missing_count, repeating_count)
return changes_needed
Case | How to Handle |
---|---|
Null or Empty Password | Return the minimum number of operations (3) as an empty password needs at least one of each character type added and at least the minimum length reached. |
Password length is exactly equal to the minimum requirement (6), but doesn't meet all character requirements. | Calculate the number of missing character types and return the maximum of that number and the number of replacements needed. |
Password length exceeds the maximum (20) with repeating character sequences and missing character types. | Prioritize deletions to reduce the length, and then apply replacement operations strategically, giving preference to the most frequent repeating sequences. |
Password contains only one type of character (e.g., 'aaaaaaaaaa'). | Replace characters within repeating sequences to introduce the missing character types after any necessary deletions. |
Long repeating sequences (length > 3) appear multiple times throughout the password. | Greedily target the longest repeating sequences first for deletion or replacement to minimize the number of operations. |
Password meets length and character type requirements but has many short repeating sequences (length 3). | Replace characters within these sequences to break them up without increasing length, then check the number of missing types. |
Integer overflow during calculations of needed deletions/insertions/replacements. | Use `long` or equivalent data type to store intermediate operation counts and avoid overflow, casting back to `int` only for the final result ensuring it fits within the valid range. |
Password length is close to minimum length 6 and requires insertions to satisfy character criteria. | Prioritize insertions of missing character types over replacements of existing characters to satisfy all conditions with minimum operations. |