420. Strong Password Checker
A password is considered strong if the below conditions are all met
- It has at least 6 characters and at most 20 characters.
- It contains at least one lowercase letter, at least one uppercase letter, and at least one digit.
- It does not contain three repeating characters in a row (i.e., “Baaabb0” 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:
- Insert one character to password,
- Delete one character from password, or
- Replace one character of password with another character.
Example 1:
Input: password = “a”
Output: 5
Example 2:
Input: password = “aA1”
Output: 3
Example 3:
Input: password = “1337C0d3”
Output: 0
Constraints:
- 1 <= password.length <= 50
- password consists of letters, digits, dot ‘.’ or exclamation mark ‘!’.
From: LeetCode
Link: 420. Strong Password Checker
Solution:
Ideas:
1. Character Type Check: The program first checks if the password has at least one lowercase letter, one uppercase letter, and one digit. If any of these are missing, they need to be added.
2. Repeating Characters: It identifies sequences of three or more consecutive repeating characters. For every sequence of length 3 or more, replacements are needed to break the repetition. The number of replacements depends on the length of these sequences.
3. Handling Password Length:
- Too Short (less than 6): Add characters to make the password at least 6 characters long. The number of steps will be the maximum between adding characters to reach 6 or adding any missing character types (lowercase, uppercase, digit).
- Valid Length (6 to 20): Fix any repeating characters and ensure the required character types (lowercase, uppercase, digit) are present. The number of steps is the maximum between fixing repeating sequences and missing types.
- Too Long (more than 20): First, delete excess characters to bring the password length down to 20. Then, optimize deletions on repeating character sequences to minimize the number of replacements needed.
4. Optimization: For long passwords, it minimizes the number of replacements needed by prioritizing deletions on specific sequences based on their length modulo 3, ensuring fewer replacements are required.
Code:
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int strongPasswordChecker(char* password) {
int len = strlen(password);
int hasLower = 0, hasUpper = 0, hasDigit = 0;
for (int i = 0; i < len; i++) {
if (islower(password[i])) hasLower = 1;
if (isupper(password[i])) hasUpper = 1;
if (isdigit(password[i])) hasDigit = 1;
}
// Count the number of missing types (lowercase, uppercase, digit)
int missingTypes = (!hasLower) + (!hasUpper) + (!hasDigit);
int replace = 0; // Number of replacements needed for repeating characters
int oneMod3 = 0, twoMod3 = 0; // Tracks sequences of length % 3 == 1 or 2
// Count repeat sequences and classify them by mod 3
for (int i = 2; i < len; ) {
if (password[i] == password[i - 1] && password[i] == password[i - 2]) {
int length = 2;
while (i < len && password[i] == password[i - 1]) {
length++;
i++;
}
replace += length / 3;
if (length % 3 == 0) oneMod3++; // Sequences of length % 3 == 0
else if (length % 3 == 1) twoMod3++; // Sequences of length % 3 == 1
} else {
i++;
}
}
if (len < 6) {
return MAX(missingTypes, 6 - len);
} else if (len <= 20) {
return MAX(missingTypes, replace);
} else {
int excessLength = len - 20;
// First, apply deletions to sequences where length % 3 == 0
replace -= MIN(excessLength, oneMod3);
// Then, apply deletions to sequences where length % 3 == 1
replace -= MIN(MAX(excessLength - oneMod3, 0), twoMod3 * 2) / 2;
// Finally, use remaining deletions for the rest of the sequences
replace -= MAX(excessLength - oneMod3 - 2 * twoMod3, 0) / 3;
return excessLength + MAX(missingTypes, replace);
}
}