# Strong Password Checker II
**Difficulty:** EASY
[External](https://leetcode.com/problems/strong-password-checker-ii)
Canonical: https://scaleengineer.com/dsa/problems/strong-password-checker-ii
**Data structures:** String
---
## Problem
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
## 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.
**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.
**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.
### Explanation
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.
```java
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;
    }
}
```
### 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`.

## Single Pass with Flags
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.
**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.
**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.
### Explanation
The algorithm combines all six checks into a single iteration over the password string for optimal performance.
1.  **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 `false` without any further processing.
2.  **Initialization**: Four boolean flags (`hasLower`, `hasUpper`, `hasDigit`, `hasSpecial`) are initialized to `false`. A string containing all valid special characters is defined for easy lookup.
3.  **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 returns `false`.
    *   **Character Type Check**: The current character is checked against the different type criteria. If it's a lowercase letter, `hasLower` is set to `true`. If it's an uppercase letter, `hasUpper` is set to `true`, 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 to `true`, it stays `true`.
4.  **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 returns `false`.
```java
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;
    }
}
```
### Algorithm
- First, check if the password's length is less than 8. If it is, return `false`.
- Initialize four boolean flags: `hasLowercase`, `hasUppercase`, `hasDigit`, `hasSpecial` to `false`.
- Create a string or set of the allowed special characters: `"!@#$%^&*()-+"`.
- Loop through the password string from `i = 0` to `length - 1`.
- Inside the loop, for the character `c` at index `i`:
    - If `i > 0`, check if `c` is the same as the character at `i-1`. If so, return `false`.
    - Check if `c` is a lowercase letter. If yes, set `hasLowercase = true`.
    - Check if `c` is an uppercase letter. If yes, set `hasUppercase = true`.
    - Check if `c` is a digit. If yes, set `hasDigit = true`.
    - Check if `c` is in the set of special characters. If yes, set `hasSpecial = true`.
- After the loop, return the result of `hasLowercase && hasUppercase && hasDigit && hasSpecial`.

# Solutions
### Java

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

```

### CPP

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

```

### Python

```python
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 == 15

```
