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., "...aaa..." is weak, but "...aa...a..." is strong, assuming other conditions are met).

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 '!'.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Solution:
    type_sets = [
        set('abcdefghijklmnopqrstuvwxyz'),
        set('ABCDEFGHIJKLMNOPQRSTUFVWXYZ'),
        set('0123456789'),
    ]
    
    def strongPasswordChecker(self, password: str) -> int:
        chars = set(password)

        # Check rule 1
        num_req_inserts = max(0, 6 - len(password))
        num_req_deletes = max(0, len(password) - 20)

        # Check rule 2
        num_req_types = 0
        for t in self.type_sets:
            num_req_types += 0 if (chars & t) else 1

        # Check rule 3
        groups = [len(list(grp)) for _, grp in itertools.groupby(password)]
        for _ in range(num_req_deletes):
            # Apply best delete
            idx, _ = min(
                enumerate(groups),
                # Ignore groups of length < 3
                # 5 - it[1] > 2 when it[1] < 3
                key=lambda it: it[1] % 3 if it[1] >= 3 else 5,
            )
            groups[idx] -= 1

        num_req_group_replaces = sum(
            group // 3
            for group in groups
        )

        return (
            num_req_deletes
            + max(
                num_req_types,
                num_req_group_replaces,
                num_req_inserts,
                )
            )