找到给定字符串的所有可能组合时,为什么字符串的第一个字符会重复出现?

我的问题可能不清楚,但我正在尝试获取字符串的所有可能的10个字符长度的组合。这是我的代码:

def printPwd(set,k):
    n = len(set)
    pwdRec(set,"",n,k)

def pwdRec(set,prefix,k):
    if k==0:
        print(prefix)
        return

    for i in range(n):
        nPrefix = prefix + set[i]
        nk = k-1
        pwdRec(set,nPrefix,nk)

chars = list("abcdefghijklmno.@-_&")
length = 10

printPwd(chars,length)

它输出如下内容:

aaaaabcde@
aaaaabcde-
aaaaabcde_
aaaaabcdfg
...

我得到五个“ a”,我不知道如何解决

zml8821929 回答:找到给定字符串的所有可能组合时,为什么字符串的第一个字符会重复出现?

注意:此答案给出了正确的输出,但我无法弄清楚它为什么起作用

您应该问的问题不是

  

“为什么我会得到五个'a'?”

但是

  

“我为什么不得到十个'a'?”

。该算法的预期输出为:

aaaaaaaaaa
aaaaaaaaab
aaaaaaaaac
aaaaaaaaad
aaaaaaaaae
...

但是您的起点是

aaaaj@bc
aaaaaaj@bd
aaaaaaj@be
aaaaaaj@bf

实际上,正在发生一些令人担忧的事情。输出甚至不确定,每次运行它都会得到不同的结果!我实际上还没有弄清楚,所以评论员请协助。如果我在调试中运行此命令,则单击缓慢,将得到正确的输出。我还可以通过向函数添加少量睡眠来纠正输出,如下所示:

import time

def printPwd(set,k):
    n = len(set)
    pwdRec(set,"",n,k)

def pwdRec(set,prefix,k):
    time.sleep(0.000001)
    if k==0:
        print(prefix)
        return

    for i in range(n):
        nPrefix = prefix + set[i]
        nk = k-1
        pwdRec(set,nPrefix,nk) #alex067's change here plus my change


chars = list("abcdefghijklmno.@-_&")
length = 10

printPwd(chars,length)

看来我们在某种类型的可变类型或非原子操作上犯规,但我尚未找到它。

alex067的评论 进行@ alex067建议的更改似乎一开始会解决输出问题,但是在前两个循环之后会出现超出范围的错误,因为您的集合不再长n。您实际上还错过了一些排列,其中第一个是aaaaaaaaba,因此它根本不是固定的,但至少是确定性的。

,

我能想到的最好的答案是“为什么不呢?”该密码不能包含重复项,但是您的代码中没有任何内容可以强制执行该操作。相反,您的程序只是生成由字符集组成的一定长度的所有字符串。

@SimonN的说法是,您的输出应以10'a的字符串开头,这是正确的,而且确实如此。当写入文件时,第一个字符串的确是'aaaaaaaaaaaa',这使我相信观察到的输出差异纯粹是图形的,这是由大量快速连续打印的字符串引起的。

@ alex067的建议也不能解决问题,因为它不仅仍然导致重复的字符,而不是使用后仅删除单个字符,而是删除其中的所有字符。名单。最后一点意味着,例如对于长度为3的密码,将省略完全有效的字符串acbbac等。当然,我们可以使用prefix[i:]来代替prefix[i+1:],但这只会使我们摆脱前一个问题,而不会摆脱后一个问题。


您现在知道,itertools提供了可能是最好的解决方案,下面将对此进行介绍。但是,在此之前,这是一个我觉得很好的递归方法:

def pwd_rec(curr_charset: str,curr_pwd: str,pwd_len: int) -> List[str]:
    result_strs = []
    for idx,curr_char in enumerate(curr_charset):
        new_pwd = curr_pwd + curr_char
        if len(new_pwd) == pwd_len:
            result_strs.append(new_pwd)
        else:
            result_strs.extend(pwd_rec(curr_charset[:idx] + curr_charset[idx+1:],new_pwd,pwd_len))
    return result_strs

这是该方法的惰性版本,使用生成器而不是列表:

def pwd_rec(curr_charset: str,pwd_len: int) -> Iterator[str]:
    for idx,curr_char in enumerate(curr_charset):
        new_pwd = curr_pwd + curr_char
        if len(new_pwd) == pwd_len:
            yield new_pwd
        else:
            yield from pwd_rec(curr_charset[:idx] + curr_charset[idx+1:],pwd_len)

如所承诺的,这是使用itertools的方法:

import itertools as itt

def pwd_perms(charset: str,pwd_len: int) -> Iterator[str]:
    for curr in itt.permutations(charset,pwd_len):
        yield ''.join(curr)

让我知道您是否有任何问题:)

本文链接:https://www.f2er.com/3026367.html

大家都在问