Strong Password Checker II
EasyPrompt
A password is said to be strong if it satisfies all the following criteria:
- It has at least
8characters. - It contains at least one lowercase letter.
- It contains at least one uppercase letter.
- It contains at least one digit.
- It contains at least one special character. The special characters are the characters in the following string:
"!@#$%^&*()-+". - It does not contain
2of the same character in adjacent positions (i.e.,"aab"violates this condition, but"aba"does not).
Given a string password, return true if it is a strong password. Otherwise, return false.
Example 1:
Input: password = "IloveLe3tcode!"
Output: true
Explanation: The password meets all the requirements. Therefore, we return true.Example 2:
Input: password = "Me+You--IsMyDream"
Output: false
Explanation: The password does not contain a digit and also contains 2 of the same character in adjacent positions. Therefore, we return false.Example 3:
Input: password = "1aB!"
Output: false
Explanation: The password does not meet the length requirement. Therefore, we return false.
Constraints:
1 <= password.length <= 100passwordconsists of letters, digits, and special characters:"!@#$%^&*()-+".
Approaches
2 approaches with complexity analysis and trade-offs.
This approach uses regular expressions (regex) to validate most of the password criteria. Regular expressions provide a powerful and declarative way to define patterns for string matching. However, for this specific problem, checking for adjacent identical characters is cumbersome with regex, so a separate loop is still needed for that condition.
Algorithm
- Check if
password.length()is less than 8. If so, returnfalse. - Iterate from the first to the second-to-last character of the password. In each iteration, check if
password.charAt(i)is equal topassword.charAt(i + 1). If they are equal, returnfalse. - Use the regex pattern
.*[a-z].*to check for the presence of a lowercase letter. If not found, returnfalse. - Use the regex pattern
.*[A-Z].*to check for the presence of an uppercase letter. If not found, returnfalse. - Use the regex pattern
.*\\d.*to check for the presence of a digit. If not found, returnfalse. - Use the regex pattern
.*[!@#$%^&*()+-].*to check for the presence of a special character. If not found, returnfalse. - If all checks pass, return
true.
Walkthrough
The overall logic is to check each of the six conditions.
- Length Check: First, we verify if the password's length is at least 8. If not, we immediately return
false. - Adjacent Character Check: We iterate through the password string with a simple loop to ensure no two adjacent characters are the same. This is easier to do with a loop than with a complex negative lookahead in regex. If we find a pair, we return
false. - Character Type Checks: For the remaining four conditions (presence of lowercase, uppercase, digit, and special character), we use separate regex patterns.
.*[a-z].*checks for at least one lowercase letter..*[A-Z].*checks for at least one uppercase letter..*\\d.*checks for at least one digit..*[!@#$%^&*()+-].*checks for at least one special character. We compile each pattern and match it against the password. The final result istrueonly if all these checks pass.
import java.util.regex.Pattern; class Solution { public boolean strongPasswordCheckerII(String password) { if (password.length() < 8) { return false; } // Check for adjacent identical characters for (int i = 0; i < password.length() - 1; i++) { if (password.charAt(i) == password.charAt(i + 1)) { return false; } } // Regex for character types boolean hasLower = Pattern.compile(".*[a-z].*").matcher(password).matches(); if (!hasLower) return false; boolean hasUpper = Pattern.compile(".*[A-Z].*").matcher(password).matches(); if (!hasUpper) return false; boolean hasDigit = Pattern.compile(".*\\d.*").matcher(password).matches(); if (!hasDigit) return false; // Note: Hyphen '-' needs to be escaped or placed at the end inside [] boolean hasSpecial = Pattern.compile(".*[!@#$%^&*()+-].*").matcher(password).matches(); if (!hasSpecial) return false; return true; }}Complexity
Time
O(N), where N is the length of the password. The loop for adjacent characters takes O(N) time. Each regex match also takes O(N) time in the worst case. Since we perform a constant number of passes, the total time complexity is linear.
Space
O(1). The space used by the regex engine is typically constant for these simple patterns and does not scale with the input size.
Trade-offs
Pros
Code can be concise and declarative for the character type checks.
Cons
Generally slower than a manual single-pass loop due to the overhead of compiling and executing regular expressions.
The check for adjacent characters doesn't fit neatly into the regex approach, requiring a separate loop.
Regex patterns can be less readable for developers not familiar with them.
This is the most efficient approach. It involves iterating through the password string just once while using a set of boolean flags to track whether each character type requirement (lowercase, uppercase, digit, special) has been met. The adjacent character rule is also checked within the same loop.
Algorithm
- First, check if the password's length is less than 8. If it is, return
false. - Initialize four boolean flags:
hasLowercase,hasUppercase,hasDigit,hasSpecialtofalse. - Create a string or set of the allowed special characters:
"!@#$%^&*()-+". - Loop through the password string from
i = 0tolength - 1. - Inside the loop, for the character
cat indexi:- If
i > 0, check ifcis the same as the character ati-1. If so, returnfalse. - Check if
cis a lowercase letter. If yes, sethasLowercase = true. - Check if
cis an uppercase letter. If yes, sethasUppercase = true. - Check if
cis a digit. If yes, sethasDigit = true. - Check if
cis in the set of special characters. If yes, sethasSpecial = true.
- If
- After the loop, return the result of
hasLowercase && hasUppercase && hasDigit && hasSpecial.
Walkthrough
The algorithm combines all six checks into a single iteration over the password string for optimal performance.
- Initial Length Check: The function first checks if the password length is at least 8. This is a quick exit condition; if the length is insufficient, we return
falsewithout any further processing. - Initialization: Four boolean flags (
hasLower,hasUpper,hasDigit,hasSpecial) are initialized tofalse. A string containing all valid special characters is defined for easy lookup. - Single Pass Iteration: The code then iterates through each character of the password.
- Adjacent Character Check: For each character from the second one onwards (
i > 0), it's compared with the preceding character (password.charAt(i-1)). If they are identical, the password violates a rule, and the function immediately returnsfalse. - Character Type Check: The current character is checked against the different type criteria. If it's a lowercase letter,
hasLoweris set totrue. If it's an uppercase letter,hasUpperis set totrue, and so on for digits and special characters. Using flags ensures that we only need to find one of each type; once a flag is set totrue, it staystrue.
- Adjacent Character Check: For each character from the second one onwards (
- Final Validation: After the loop completes, all characters have been processed. The function returns the logical AND of the four boolean flags. If all flags are
true, it means all character type requirements were met, and we already know the length and adjacent character rules were satisfied. Otherwise, it returnsfalse.
class Solution { public boolean strongPasswordCheckerII(String password) { if (password.length() < 8) { return false; } boolean hasLower = false; boolean hasUpper = false; boolean hasDigit = false; boolean hasSpecial = false; String specialChars = "!@#$%^&*()-+"; for (int i = 0; i < password.length(); i++) { char c = password.charAt(i); if (i > 0 && c == password.charAt(i - 1)) { return false; } if (Character.isLowerCase(c)) { hasLower = true; } else if (Character.isUpperCase(c)) { hasUpper = true; } else if (Character.isDigit(c)) { hasDigit = true; } else if (specialChars.indexOf(c) != -1) { hasSpecial = true; } } return hasLower && hasUpper && hasDigit && hasSpecial; }}Complexity
Time
O(N), where N is the length of the password. We perform a single pass through the string, and each operation inside the loop (character comparison, type checking) takes constant time.
Space
O(1). We only use a few boolean variables and a constant-size string for special characters, regardless of the input password's length.
Trade-offs
Pros
Optimal time complexity as it requires only one pass over the data.
Minimal space usage.
The logic is straightforward, easy to read, and maintain.
Cons
No significant disadvantages for this problem, as it's the most direct and efficient solution.
Solutions
Solution
class Solution {public boolean strongPasswordCheckerII(String password) { if (password.length() < 8) { return false; } int mask = 0; for (int i = 0; i < password.length(); ++i) { char c = password.charAt(i); if (i > 0 && c == password.charAt(i - 1)) { return false; } if (Character.isLowerCase(c)) { mask |= 1; } else if (Character.isUpperCase(c)) { mask |= 2; } else if (Character.isDigit(c)) { mask |= 4; } else { mask |= 8; } } return mask == 15; }}class Solution {public: bool strongPasswordCheckerII(string password) { if (password.size() < 8) { return false; } int mask = 0; for (int i = 0; i < password.size(); ++i) { char c = password[i]; if (i && c == password[i - 1]) { return false; } if (c >= 'a' && c <= 'z') { mask |= 1; } else if (c >= 'A' && c <= 'Z') { mask |= 2; } else if (c >= '0' && c <= '9') { mask |= 4; } else { mask |= 8; } } return mask == 15; }};class Solution: def strongPasswordCheckerII(self, password: str) -> bool: if len(password) < 8: return False mask = 0 for i, c in enumerate(password): if i and c == password[i - 1]: return False if c . islower(): mask |= 1 elif c . isupper(): mask |= 2 elif c . isdigit(): mask |= 4 else: mask |= 8 return mask == 15Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.