【问题标题】:Python recursion permutationsPython递归排列
【发布时间】:2012-10-18 00:55:05
【问题描述】:

我在尝试使用递归创建排列代码时遇到了麻烦。这假设将一个列表返回给使用,其中包含每个字母的所有可能位置。所以对于 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)

那里有步骤,但我不知道如何使用它们

【问题讨论】:

  • 我不知道你为什么要写这个,但你也可以使用itertools.permutations()。它使用yield,因此不必构造整个列表。
  • 我还没有学会如何使用yield。所以我想知道是否有办法在不使用 yeild 的情况下执行此代码
  • 你为什么不检查 Numpy.. 我认为它提供了这些功能。虽然不确定
  • @brianChiem, itertools.permutations() 使用 yield 对您来说基本上是透明的,所以试一试。如果您不打算在 for 循环中对其进行迭代,请使用 list(itertools.permutations(...)

标签: python recursion permutation


【解决方案1】:

你想做递归,所以你首先要弄清楚递归是如何工作的。在这种情况下,它是以下内容:

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

这有帮助吗?

【讨论】:

  • 所以对于没有元素 a 的 z = s plst = permutations(s[1:]) 是否适用
  • 是的,但是你必须对 s 的每个元素都这样做。所以下一个(去掉'b')是permutations(s[0] + s[2:])。请注意,“a”包含在此子集中。
  • 递归调用在哪里?不应该是for each t in permutations(z): perm_list.append([a]+t])吗?
  • @tobias_k:是的,我看过了!我现在已经更正了。
  • 我不确定我应该在这部分放什么 perm_list.append([a] + t) 我认为这是递归调用,但我不确定。我在想我应该把 permutations(s[1:]) +permutation(s[0])
【解决方案2】:

当你迷失在递归函数中时,你应该画出调用树。以下版本(启发@Ben 答案)保持输入顺序(如果输入按字典顺序排列,则排列列表将为'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

以下版本适用于字符串和列表,注意重构步骤不一样:

def permut(array):
    if len(array) == 1:
        return [array]
    res = []
    for permutation in permut(array[1:]):
        for i in range(len(array)):
            res.append(permutation[:i] + array[0:1] + permutation[i:])
    return res

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

【讨论】:

    【解决方案3】:

    递归地考虑基本情况并根据这种直觉进行构建。

    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
    

    【讨论】:

      【解决方案4】:
      def permutations(string_input, array, fixed_value=""):
          for ch in string_input:
              permutations(string_input.replace(ch, ""), array, fixed_value + ch)
          if not string_input:
              array.append(fixed_value)
      

      你可以调用它

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

      【讨论】:

        【解决方案5】:

        我知道这也是一个我,但我认为这对某些人来说可能更容易理解......

        1. 基本情况是输入只有一个字符。
        2. 设置循环遍历字符串中的每个字母。
        3. 另一个 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
          

        【讨论】:

          【解决方案6】:

          这是我想出的最简单的解决方案。

             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)
          

          【讨论】:

            【解决方案7】:

            您可以使用在列表中迭代索引的函数,并生成一个列表,该列表由索引处的值和其余列表值的排列组成。下面是一个使用 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(permutations('abc')) 返回:

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

            【讨论】:

              【解决方案8】:

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

              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()
              

              【讨论】:

                【解决方案9】:
                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,""))] 
                

                【讨论】:

                  【解决方案10】:

                  通过递归进行排列的最简单方法 是先为问题设想一个递归树

                  基本情况:如果给定一个空列表排列将是 [ [] ] 然后我们只想从列表中删除一个项目并将其添加到列表其余部分的所有索引中。

                  eg input : [a,b,c]
                  first = a
                  rest = [b,c]
                  all = [a,b,c] , [b,a,c] , [b,c,a]
                  

                  Time: O(N!) #这是最好的,因为我们正在创建 N!元素
                  Space O(N^2) #N stack frame * N item in per_with_all

                  来源: https://www.youtube.com/watch?v=us0cYQXQpxg

                  def permetutation(arr):
                      if len(arr) == 0:
                          return [ [] ]
                      #We remove 1st item from error as at each level we introduce 1 item 
                      first_elenment = arr.pop(0)
                  
                      #getting permet for all other item 
                      perm_without_first = permetutation(arr)
                  
                      per_with_all = []
                  
                      #Add permtution to every index 
                      for comb in perm_without_first:
                          for ind in range(len(comb)+1): #We also wan to add elenment to last so do +1 
                              all = comb[0:ind] + [first_elenment] + comb[ind:] 
                              per_with_all.append( all)
                  
                      return per_with_all
                  

                  【讨论】:

                    猜你喜欢
                    • 2016-06-19
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-06-18
                    • 2011-07-23
                    • 1970-01-01
                    • 2013-06-13
                    相关资源
                    最近更新 更多