web-dev-qa-db-ja.com

Python再帰順列

再帰を使用して順列コードを作成しようとして問題が発生しています。これは、各文字のすべての可能な位置でリストを使用に戻すことを想定しています。したがって、Word 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)

そこには手順がありますが、それらの使用方法がわかりません

8
brian Chiem

再帰を実行したいので、最初に再帰がどのように機能するかを確認する必要があります。この場合、次のようになります。

permutation [a,b,c,...] = [a + permutation[b,c,...], b + permutation[a,c,..], ...]

そして最終条件として:

permutation [a] = [a]

したがって、再帰はリストをサブリストに分割し、毎回1つの要素を抽出します。次に、この要素がサブリストの各順列の前に追加されます。

したがって、擬似コードでは:

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

これは役に立ちますか?

27
Ben Ruijl

再帰的に、基本ケースについて考え、その直感から構築します。

1)文字「c」が1つしかない場合はどうなりますか?その要素の順列は1つしかないため、その要素のみを含むリストを返します。

2)最後の順列を指定して次の順列を生成するにはどうすればよいですか?前の順列「c」のすべての可能な位置に追加の文字「a」を追加すると、「ca」、「ac」が得られます。

3)以前の各順列のすべての可能な位置に文字を追加することで、ますます大きな順列を構築し続けることができます。

次のコードは、文字列の文字数が1文字以下の場合、1文字のリストを返します。それ以外の場合、文字列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
8
stroz

再帰関数に迷ったときは、呼び出しツリーを描画する必要があります。次のバージョン(@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

演習として、これらの関数の呼び出しツリーを描画する必要がありますが、何か気づきましたか?

5
Maxime

これは私が思いついた最も簡単な解決策です。

   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)
1
eddd
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
1

リストを介してインデックスを反復処理する関数を使用して、インデックスの値とそれに続く残りのリスト値の順列で構成されるリストを生成できます。以下は、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']]
_
1
blhsing

これも私だと思いますが、理解しやすい方もいらっしゃると思います。

  1. 基本的なケースは、入力が1文字だけの場合です。
  2. 文字列内の各文字を反復処理するforループを設定します。
  3. 別のforループは、他のすべての可能性を再帰的に並べ替えます。

def順列:

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
0
sparrow