Python 2299.py
class Solution:
def strongPasswordCheckerII(self, password: str) -> bool:
# (1) It has at least 8 characters.
if len(password) < 8:
return False
rule2 = False # (2) It contains at least one lowercase letter.
rule3 = False # (3) It contains at least one uppercase letter.
rule4 = False # (4) It contains at least one digit.
rule5 = False # (5) It contains at least one special character.
# The special characters are the characters in the following string:
# "!@#$%^&*()-+"
# (6) It does not contain 2 of the same character in adjacent positions
# (i.e., "aab" violates this condition, but "aba" does not).
last = ""
for c in password:
if "a" <= c <= "z":
rule2 = True
elif "A" <= c <= "Z":
rule3 = True
elif "0" <= c <= "9":
rule4 = True
elif c in "!@#$%^&*()-+":
rule5 = True
if c == last:
return False
last = c
return rule2 and rule3 and rule4 and rule5
Difficulty
and has an acceptance rate of about 56% (100k+ submissions).
Typical patterns to solve this problem:
- String
AI Disclaimer
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.
See this dedicated page for more details.
Code Walkthrough
Overview
The provided implementation defines a method that validates whether a given password satisfies a set of six security rules. The function proceeds in a linear fashion: it first checks the minimum length, then iterates through the characters once, updating flags that record the presence of required character classes while simultaneously detecting any adjacent duplicate characters. The final result is the logical conjunction of the four presence flags, which are only evaluated after the loop completes.
Length Verification
The very first operation is a guard clause that returns False immediately if the password length is less than eight characters. This early exit prevents any further processing for inputs that cannot possibly satisfy the policy, saving work for short strings.
if len(password) < 8:
return False
Flag Initialization
Four Boolean variables are created to track the discovery of lowercase letters, uppercase letters, digits, and special characters. All are initialized to False. An additional variable, last, holds the previous character to enable adjacency checking.
rule2 = False # lowercase present
rule3 = False # uppercase present
rule4 = False # digit present
rule5 = False # special character present
last = ""
Single-Pass Character Classification
The core of the algorithm is a for loop that examines each character exactly once. Inside the loop, a series of chained comparisons determines the character class:
- The range
"a" <= c <= "z"identifies lowercase letters. - The range
"A" <= c <= "Z"identifies uppercase letters. - The range
"0" <= c <= "9"identifies digits. - Membership in the literal string
"!@#$%^&*()-+"identifies allowed special symbols.
When a character matches a class, the corresponding flag is set to True. Because the flags are only ever set to True, there is no need to reset them, and the loop does not perform any redundant work once a flag has been satisfied.
for c in password:
if "a" <= c <= "z":
rule2 = True
elif "A" <= c <= "Z":
rule3 = True
elif "0" <= c <= "9":
rule4 = True
elif c in "!@#$%^&*()-+":
rule5 = True
Adjacent Duplicate Detection
Immediately after classifying the character, the algorithm compares it with the previously seen character stored in last. If the two are identical, the function returns False on the spot, halting further iteration. This early termination avoids unnecessary processing for passwords that already violate the adjacency rule.
if c == last:
return False
last = c
Final Decision
After the loop finishes, the method returns the logical and of the four presence flags. Because the length and adjacency conditions have already been enforced, the final expression confirms that the password contains at least one character from each required class.
return rule2 and rule3 and rule4 and rule5
Edge Cases Handled
The code gracefully handles several boundary conditions:
- An empty string fails the length check instantly.
- A string exactly eight characters long proceeds to the loop, ensuring that the minimum length requirement is inclusive.
- Passwords composed solely of characters from a single required class (e.g., only digits) will leave the other flags
False, causing the final conjunction to evaluate toFalse. - Strings that contain a repeated character at any position, including the first two characters, trigger the adjacency check and return
Falsewithout scanning the remainder. - Passwords that include characters outside the defined special set are simply ignored for the special-character flag, allowing the function to focus only on the permitted symbols.
Performance Optimizations
The implementation exhibits several efficiency choices:
- Early length guard eliminates work for obviously invalid inputs.
- Single traversal ensures that each character is examined only once, achieving the minimal number of passes required for the rule set.
- Immediate adjacency failure returns as soon as a duplicate is found, preventing the rest of the password from being processed.
- Flag setting without resetting means each flag is written at most once per password, avoiding unnecessary assignments after a flag becomes
True. - Use of range comparisons (
"a" <= c <= "z") leverages the underlying character ordering, which is faster than invoking methods likestr.islower(). - Membership test against a literal string for special characters is a constant-time operation because the string is short and Python optimizes such containment checks.
Collectively, these decisions keep the runtime proportional to the length of the password while minimizing overhead per character.
ELI5 - Simplified Explanation
Think of this code like a guard standing at the front door to check if a password is strong enough to keep a secret safe. The code looks at the word you picked like a detective investigating clues.
First, the guard uses a tape measure to make sure the password is at least eight letters long because short passwords are too easy for someone to guess. If it is too short, the guard shakes their head and says it does not work.
Next, the code walks through every letter in the word one by one. It keeps a mental checklist in its pocket to see if the word has a small letter, a big letter, a number, and a special sign like an exclamation point or a plus sign. If it finds one of these, it puts a checkmark on its list.
While it looks at the letters, the guard also watches to see if two of the same letter are standing right next to each other, like a pair of twins holding hands. If it sees twins, it stops immediately because that would make the password less secure.
Finally, after looking at the whole password, the guard checks its pocket list. If all four checkmarks are there and no twins were spotted standing together, the password passes the test and is ready to keep everything safe inside.
Code Quality
Complexity Analysis
As a rule of thumb, the maximum input size for one second execution time is
- factorial: up to 10 elements
- exponential: up to 20 elements
- polynomial: a few thousand elements
- loglinear: up to 100,000 elements
- linear: a few million elements
- logarithmic: a billion elements
- constant: practically unlimited
Other Solutions
Obviously, I did that after I solved the problem myself.
In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.
And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.
(click on a column header to sort the table)
| author | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| author | solutions | |||||||||
| www | AlgoMonster | Java | Python | C++ | TS | |||||
| WalkCCC | Java | Python | C++ | |||||||
| leetcode.ca | Java | Python | C++ | C | Go | Rust | TS | |||
| Progiez | Java | Python | C++ | |||||||
| github | charles-wangkai | Java | ||||||||
| fartem | Ruby | |||||||||
| fsq | C++ | |||||||||
| JoshCrozier | JS | |||||||||
| lkwq007 | Python | |||||||||
| varunu28 | Java | |||||||||
| AlgoMonster | C++, Python, Java, TypeScript | |||||||||
| WalkCCC | C++, Python, Java | |||||||||
| leetcode.ca | C, C++, Go, Java, Python, Rust, TypeScript | |||||||||
| Progiez | C++, Java, Python | |||||||||
| charles-wangkai | Java | |||||||||
| fartem | Ruby | |||||||||
| fsq | C++ | |||||||||
| JoshCrozier | JavaScript | |||||||||
| lkwq007 | Python | |||||||||
| varunu28 | Java |
Videos
Similar Problems
- problem 468: Validate IP Address
Solved On The Same Day
- problem 1375: Number of Times Binary String Is Prefix-Aligned
- problem 1899: Merge Triplets to Form Target Triplet
- problem 2348: Number of Zero-Filled Subarrays
- problem 2870: Minimum Number of Operations to Make Array Empty
Extra
- Tech Stack - my development environment and tools
- AI - how AI helped me create this website (NOT solving the problems)
- Progress - progression over time
- Quality - code quality