Strong Password Checker II

EASY

Description

A password is said to be strong if it satisfies all the following criteria:

  • It has at least 8 characters.
  • 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 2 of 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 <= 100
  • password consists of letters, digits, and special characters: "!@#$%^&*()-+".

Approaches

Checkout 2 different approaches to solve Strong Password Checker II. Click on different approaches to view the approach and algorithm in detail.

Regular Expression Matching

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, return false.
  • Iterate from the first to the second-to-last character of the password. In each iteration, check if password.charAt(i) is equal to password.charAt(i + 1). If they are equal, return false.
  • Use the regex pattern .*[a-z].* to check for the presence of a lowercase letter. If not found, return false.
  • Use the regex pattern .*[A-Z].* to check for the presence of an uppercase letter. If not found, return false.
  • Use the regex pattern .*\\d.* to check for the presence of a digit. If not found, return false.
  • Use the regex pattern .*[!@#$%^&*()+-].* to check for the presence of a special character. If not found, return false.
  • If all checks pass, return true.

The overall logic is to check each of the six conditions.

  1. Length Check: First, we verify if the password's length is at least 8. If not, we immediately return false.
  2. 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.
  3. 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 is true only 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 Analysis

Time Complexity: 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 Complexity: O(1). The space used by the regex engine is typically constant for these simple patterns and does not scale with the input size.

Pros and Cons

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.

Code Solutions

Checking out 3 solutions in different languages for Strong Password Checker II. Click on different languages to view the code.

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;
  }
}

Video Solution

Watch the video walkthrough for Strong Password Checker II



Data Structures:

String

Subscribe to Scale Engineer newsletter

Learn about System Design, Software Engineering, and interview experiences every week.

No spam, unsubscribe at any time.