Python递归置换

Python递归置换,python,recursion,permutation,Python,Recursion,Permutation,我在尝试用递归生成置换代码时遇到了麻烦。假设这将返回一个列表,其中包含每个字母的所有可能位置。因此,对于单词cat来说,假设它返回['cat','act',atc','cta','tca','tac']。到目前为止,我有这个 def permutations(s): lst=[] if len(s) == 1 or len(s) == 0 : # Return a list containing the string, not the string

我在尝试用递归生成置换代码时遇到了麻烦。假设这将返回一个列表,其中包含每个字母的所有可能位置。因此,对于单词
cat
来说,假设它返回
['cat','act',atc','cta','tca','tac']
。到目前为止,我有这个

def permutations(s):
    lst=[]
    if len(s) == 1 or len(s) == 0 :
        # Return a list containing the string, not the string
        return [s]
    # Call permutations to get the permutations that don't include the
    # first character of s
    plst = permutations(s[1:])
    print(plst)
    for item in plst:
        print (item)
        plst= permutations(s[1+1:])

         # Now move through each possible position of the first character
        # and create a new string that puts that character into the strings
        # in plst
        for i in range(len(s)):
            pass
            # Create a new string out of item
            # and put it into lst
        # Modify
    for item in lst:
        print(index)

这里有一些步骤,但我不知道如何使用它们。如果你想做递归,那么你首先要知道递归是如何工作的。在这种情况下,它如下所示:

permutation [a,b,c,...] = [a + permutation[b,c,...], b + permutation[a,c,..], ...]
最后一个条件是:

permutation [a] = [a]
因此递归将列表拆分为子列表,每次提取一个元素。然后将该元素添加到子列表的每个排列的前面

所以在伪代码中:

def permutation(s):
   if len(s) == 1:
     return [s]

   perm_list = [] # resulting list
   for a in s:
     remaining_elements = [x for x in s if x != a]
     z = permutation(remaining_elements) # permutations of sublist

     for t in z:
       perm_list.append([a] + t)

   return perm_list

这有用吗?

当您在递归函数中迷失方向时,应该绘制调用树。以下版本(inspired@Ben answer)保持输入顺序(如果输入是按字典顺序排列的,则排列列表将是,
'012'->['012',021',102',120',201',210']

def permut2(mystr):
    if len(mystr) <= 1:
        return [mystr]
    res = []
    for elt in mystr:
        permutations = permut2(mystr.replace(elt, ""))
        for permutation in permutations:
            res.append(elt + permutation)
    return res

作为练习,你们应该画出这些函数的调用树,你们注意到什么了吗?

递归地,考虑基本情况,然后根据直觉构建

1) 当只有一个字符“c”时会发生什么?该元素只有一个排列,因此我们返回一个仅包含该元素的列表

2) 如果给定最后一个置换,我们如何生成下一个置换?在前面的排列“c”中的所有可能位置添加一个额外的字母“a”,则表示“ca”,“ac”

3) 我们可以通过在每个先前排列的所有可能位置添加一个附加字符来继续构建越来越大的排列

如果字符串有一个或更少的字符,下面的代码将返回一个包含一个字符的列表。否则,对于不包括字符串s[-1]中最后一个字符的所有置换,我们将为每个位置生成一个新字符串,其中可以包括该字符,并将新字符串附加到当前置换列表中

def permutations(s):
    if len(s) <= 1:
        return [s]
    else:
        perms = []
        for e in permutations(s[:-1]):
            for i in xrange(len(e)+1):
                perms.append(e[:i] + s[-1] + e[i:])
        return perms
def排列:
如属例外(s)
你可以打电话过来

array = []
permutations("cat", array)
print array

我知道这也是一个我,但我想这一个可能更容易让一些人理解

  • 基本情况是输入仅为一个字符
  • 设置一个for循环,循环遍历字符串中的每个字母
  • 另一个for循环递归地遍历所有其他可能性

    def permute(s):
    
        out = []
    
        if len(s) == 1:
            out = [s]
        else:
            for i,let in enumerate(s):
                for perm in permute(s[:i]+s[i+1:]):
                    out += [let+perm]
        return out
    

  • 这是我想出的最简单的解决办法

       def permutations(_string):
            # stores all generated permutations
            permutations = []
    
            # this function will do recursion
            def step(done, remain):
                # done is the part we consider "permutated"
                # remain is the set of characters we will use
    
                # if there is nothing left we can appened generated string
                if remain == '':
                    permutations.append(done)
                else:
    
                    # we iterate over the remaining part and indexing each character
                    for i, char in enumerate(remain):
                        # we dont want to repeat occurance of any character so pick the remaining
                        # part minus the currect character we use in the loop
                        rest = remain[:i] + remain[i + 1:]
                        # use recursion, add the currect character to done part and mark rest as remaining
                        step(done + char, rest)
            step("", _string)
            return permutations
    
    您可以使用以下工具进行测试:

    @pytest.mark.parametrize('_string,perms', (
        ("a", ["a"]),
        ("ab", ["ab", "ba"]),
        ("abc", ["abc", "acb", "cba", "cab", "bac", "bca"]),
        ("cbd", ["cbd", "cdb", "bcd", "bdc", "dcb", "dbc"])
    ))
    def test_string_permutations(_string, perms):
        assert set(permutations(_string)) == set(perms)
    

    您可以使用一个函数在列表中迭代索引,并生成一个列表,该列表由索引处的值和其余列表值的排列组成。下面是一个使用Python 3.5+功能的示例:

    def permutations(s):
        if not s:
            yield []
        yield from ([s[i], *p] for i in range(len(s)) for p in permutations(s[:i] + s[i + 1:]))
    
    因此,
    list(排列('abc'))
    返回:

    [['a', 'b', 'c'],
     ['a', 'c', 'b'],
     ['b', 'a', 'c'],
     ['b', 'c', 'a'],
     ['c', 'a', 'b'],
     ['c', 'b', 'a']]
    

    这些示例代码非常有用,但我在上进行代码练习时发现一个测试用例失败。基本上,这里所有给定的方法都忽略了是否存在任何重复

    Input: s: "ABA" 
    Output: ["ABA", "AAB", "BAA", "BAA", "AAB", "ABA"] 
    Expected Output: ["AAB", "ABA", "BAA"]
    
    因此,如果您看到,它在输出中有以下重复项:

    ["BAA", "AAB", "ABA"]
    
    我在这里一点一点地修改了这个

    def stringPermutations(s):
            news = s
            if len(news) == 1:
                return [news]
            res = []
            for permutation in stringPermutations(news[1:]):
                for i in range(len(news)):
                    res.append(permutation[:i] + news[0:1] + permutation[i:])
            # To Remove Duplicates From a Python List: list(dict.fromkeys(res))
            # To Sort List : sorted()
            return sorted(list(dict.fromkeys(res)))
    
    def main():
        arr = 'ABA'
        print(stringPermutations(arr))
    
    if __name__ == '__main__':
        main()
    
    但从时间复杂性来看,这个答案并不合适。这种方法的时间复杂度为:o(n^2)

    我认为下面的方法很合理

    def stringPermutations(string, prefix, permutation_list):
        #Edge case check
        if len(string) == 0:
            permutation_list.append(prefix)
        else:
            for i in range(len(string)):
                rem = string[0:i] + string[i + 1:]
                stringPermutations(rem, prefix + string[i], permutation_list)
        return sorted(list(dict.fromkeys(permutation_list)))
    def main():
        permutation_list = []
        print(stringPermutations('aba','', permutation_list))
    
    if __name__ == '__main__':
        main()
    
    def排列:
    ch=列表
    如果len(ch)==2:
    per=ch[1]+ch[0]
    返回[''.join(ch)]+[per]
    如果len(ch)<2:
    返回ch
    其他:
    返回[init+per for init in ch for per in permute(“”.join(ch).replace(init)”)]
    
    我不知道你为什么要写这篇文章,但你也可以使用。它使用
    yield
    ,因此它不必构建整个列表。我还没有学会如何使用yield。所以我想知道是否有一种不用yeildWhy检查Numpy的方法来完成这段代码。。我认为它提供了这些特性。不确定though@brianChiem,
    itertools.permutations()
    使用
    yield
    对您来说基本上是透明的,所以请试一试。如果您不打算在
    循环中对其进行迭代,请使用
    list(itertools.permutations(…)
    。那么对于没有元素a的z=s,plst=permutations(s[1:])对其有效吗是的,但您必须对s的每个元素都这样做。因此,下一个(删除“b”)将是
    permutations(s[0]+s[2:])
    。请注意,“a”包含在这个子集中。递归调用在哪里?对于置换(z):置换列表中的每个t,它不应该是
    。追加([a]+t])
    ?@tobias\u k:啊,是的,我检查过了!我现在已经更正了。我不确定我应该在置换列表的这部分中添加什么。追加([a]+t)我想这是递归调用,但我不确定。我在想我应该把置换(s[1:])+置换(s[0])放进去
    def stringPermutations(s):
            news = s
            if len(news) == 1:
                return [news]
            res = []
            for permutation in stringPermutations(news[1:]):
                for i in range(len(news)):
                    res.append(permutation[:i] + news[0:1] + permutation[i:])
            # To Remove Duplicates From a Python List: list(dict.fromkeys(res))
            # To Sort List : sorted()
            return sorted(list(dict.fromkeys(res)))
    
    def main():
        arr = 'ABA'
        print(stringPermutations(arr))
    
    if __name__ == '__main__':
        main()
    
    def stringPermutations(string, prefix, permutation_list):
        #Edge case check
        if len(string) == 0:
            permutation_list.append(prefix)
        else:
            for i in range(len(string)):
                rem = string[0:i] + string[i + 1:]
                stringPermutations(rem, prefix + string[i], permutation_list)
        return sorted(list(dict.fromkeys(permutation_list)))
    def main():
        permutation_list = []
        print(stringPermutations('aba','', permutation_list))
    
    if __name__ == '__main__':
        main()
    
    def permute(s):
        ch = list(s)
        if len(ch) == 2:
            per = ch[1] + ch[0] 
            return [''.join(ch)] + [per]
        if len(ch) < 2:
            return ch
        else:
            return [ init+per for init in ch for per in permute(''.join(ch).replace(init,""))]