This is a Leetcode problem -
A password is considered strong if below conditions are all met -
1. It has at least 6 characters and at most 20 characters.
2. It must contain at least one lowercase letter, at least one uppercase letter, and at least one digit.
3. It must NOT contain three repeating characters in a row (
...aaa...
is weak, but...aa...a...
is strong, assuming other conditions are met).Write a function
strong_password_checker(s)
, that takes a strings
as input, and returns the MINIMUM change required to makes
a strong password. Ifs
is already strong, return0
.Insertion, deletion or replacements of any one character are all considered as one change.
Here is my solution to this challenge -
def strong_password_checker(s: str) -> int: def has_lower(s): for c in s: if c.islower(): return 1 return 0 def has_upper(s): for c in s: if c.isupper(): return 1 return 0 def has_digits(s): for c in s: if c.isnumeric(): return 1 return 0 def find_repeats(s): i = 0 j = 0 repeats = [] while i < len(s) - 1: if s[i+1] == s[i]: i += 1 continue if (i - j + 1) > 2: repeats.append(i - j + 1) i += 1 j = i if (i - j + 1) > 2: repeats.append(i - j + 1) return repeats def repeats_after_delete(reps, d): if d >= sum([r - 2 for r in reps]): return [] reps = sorted(reps, key=lambda d: d%3) while d > 0: for i in range(len(reps)): if reps[i] < 3: continue r = reps[i] % 3 + 1 reps[i] -= min(r, d) d -= r if d <= 0: break return [r for r in reps if r > 2] def num_repeats_change(repeats): return sum([r // 3 for r in repeats]) total_changes = 0 format_changes = (1 - has_lower(s)) + (1 - has_upper(s)) + (1 - has_digits(s)) repeats = find_repeats(s) if len(s) < 6: repeat_change = num_repeats_change(repeats) total_changes = max([6 - len(s), format_changes, repeat_change]) elif len(s) > 20: repeats = repeats_after_delete(repeats, len(s) - 20) repeat_change = num_repeats_change(repeats) total_changes = len(s) - 20 + max([repeat_change, format_changes]) else: repeat_change = num_repeats_change(repeats) total_changes = max([repeat_change, format_changes]) return total_changes
Here are some example outputs -
#print(strongPasswordChecker("aaaaaaaaaaaaAsaxqwd1aaa"))
>>> 6
#Explanation - aa1aa1aa1aAsaxqwd1aa (just an example - delete three characters, add three digits to replace consecutive a's)
#print(strongPasswordChecker("aaaaa"))
>>> 2
#Explanation - aaAaa1 (just an example - add a character (so the length is at least 6), add an uppercase letter to replace consecutive a's)
#print(strongPasswordChecker("aAsaxqwd2aa"))
>>> 0
#Explanation - A strong password (all conditions are met)
Here are the times taken for each output -
%timeit strongPasswordChecker("aaaaaaaaaaaaAsaxqwd1aaa")
>>> 18.7 µs ± 1.75 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit strongPasswordChecker("aaaaa")
>>> 5.05 µs ± 594 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit strongPasswordChecker("aAsaxqwd2aa")
>>> 7.19 µs ± 469 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
So, I would like to know whether I could make this program shorter and more efficient.
Any help would be highly appreciated.