我的代码通过了验证,但运行速度很慢

My code passes validation, but runs very slowly

def is_password_good(password):
    if len(txt) > 7 and [i for i in txt if i.isupper()] and [i for i in txt if i.islower() and [i for i in txt if i.isnumeric()]]:
        return True
    else:
        return False

txt = input()

print(is_password_good(txt))

您可以迭代每个 method 作为您的条件,并在满足条件时中断以节省资源。

def is_password_good(password):
    if len(password) > 7:
        password = set(password)
        for method in (str.isupper,
                       str.islower,
                       str.isnumeric):
            for i in password:
                if method(i):
                    break
            else:
                return False
        return True
    else:
        return False
>>> is_password_good('1234567')
False
>>> is_password_good('12345678')
False
>>> is_password_good('123456aa')
False
>>> is_password_good('123456aB')
True

这个方法:

  • 条件满足时中断
    • 为了避免浪费计算时间检查已证明正确的答案
  • space 的复杂度为 O(<=n)
    • 转换为 set 删除了重复的字母
  • 可扩展以实现更多功能
    • 只需将另一个 lambda 函数添加到 method 元组

你正在 运行 三个 for 循环,一个接一个,而你可以 运行 一个 for 循环:

def is_password_good(password, good_length):
    if len(password) < good_length:
        return False

    has_upper, has_lower, has_digit = False, False, False
    for char in set(password):
        has_upper = char.isupper() or has_upper
        has_lower = char.islower() or has_lower
        has_digit = char.isdigit() or has_digit
        if has_upper and has_lower and has_digit:
            return True
    return False

想象一个所有小写字母的密码——您必须检查每个字母以查看您是否也得到了数字或大写字母,因此您将遍历所有 n unique 个字符,才能确定密码不满足要求。这意味着在 worst-case 场景中,您可能做的最好的事情是 O(n)(同样,其中 nunique 字符的数量字符串)。

然后的想法应该是尽快跳出循环——在这种情况下,一旦所有三个标志都切换到True

三个 char.isxxx() or has_xxx 语句中的每一个在第一次满足检查时将永远 True,因为在第一次之后它是 True,语句减少到 char.isxxx() or True 这将永远是真的。

三个标志都设置好后,可以break然后return是否也满足good_length

如果您正在寻找大写字母,使用您正在使用的方法,每个字母都将被评估。因此,如果您的字符串中有 50 个字母,并且您正在使用列表推导式方法,那么您将为每个列表做 50 件事。在您的情况下,有三个列表推导式,因此每次都会进行 len(txt) * 3 次评估。

使用您的方法,修改内联密码以使 timeit 调用更简单:

import timeit

def is_password_good():
    txt = "Sup3rlongpassword"
    if (
        len(txt) > 7
        and [i for i in txt if i.isupper()]
        and [i for i in txt if i.islower() and [i for i in txt if i.isnumeric()]]
    ):
        return True
    else:
        return False

>>> timeit.timeit(is_password_good)
17.099690434522927

这是一个使用正则表达式的方法。在每种情况下,一旦满足通过条件,它就会 return 值。

import re 

has_upper = re.compile('[A-Z]').search
has_lower = re.compile('[a-z]').search
has_digit = re.compile('[0-9]').search    

def is_password_good_re():
    txt = "Sup3rlongpassword"
    if len(txt) > 7 and has_upper(txt) and has_lower(txt) and has_digit(txt):
        return True
    else:
        return False

>>> timeit.timeit(is_password_good_re)
0.8171015260741115

编辑:

还有一点很突出,您的一个列表嵌套在另一个列表中。

[i for i in txt if i.islower() and [i for i in txt if i.isnumeric()]]

所以这意味着每个字符都会进行数字检查。那么如果密码有10个字符,那么对数字进行10次检查,每次检查10次,总共对数字进行100次评估。