There are two lines from A = {0,1,2,3} * It is necessary to find out whether one of them can be obtained from the other by several binary permutations and find the number of such permutations.

  1. As far as I understand, getting one from the other is to find out if the first is an anagram of the other?
  2. How can I implement "find the number of such permutations"?

2 answers 2

To find out how many pairwise exchanges (swaps) of letters are needed to turn one input string into another, when letters can be repeated, you can find all possible permutations of the indices that make another from one string ( get_permutations() ), and then calculate for each resulting permutations of the number of exchanges that it requires using the number_of_swaps(permutation) function , and select a minimum number of exchanges:

 #!/usr/bin/env python import itertools from collections import Counter, defaultdict def get_permutations(a, b): """Generate all permutations that convert *a* sequence into *b* sequence.""" positions = defaultdict(list) # letter -> "list of positions in *a*" for position, letter in enumerate(a): positions[letter].append(position) # generate all permutations choosing all available indices at each position #NOTE: using product() is not very efficient here but it is simple multiset = (positions[letter] for letter in b) for permutation in itertools.product(*multiset): if len(permutation) == len(set(permutation)): yield permutation 

This function expects that you can turn a string into b , that is, any of the following has been executed:

 # assert that we can permute *a* string into *b* assert len(a) == len(b) and all(a.count(c) == b.count(c) for c in set(a)) assert Counter(a) == Counter(b) assert sorted(a) == sorted(b) # each of the 3 assertions is enough by itself 

get_permutations(a, b) returns lists of indices (permutations) such that a turns into b :

 # assert that *permutation* permutes *a* into *b* assert [a[p] for p in permutation] == list(b) # each of the 2 is enough by itself assert all(c == a[permutation[i]] for i, c in enumerate(b)) 

Each call to get_permutations() generates m[c1]! * m[c2]! ... m[c1]! * m[c2]! ... m[c1]! * m[c2]! ... permutation, where m[ci] (multiplicity) is the number of times the letter ci repeated in the input word, eh ! this is factorial. For example, for TTAGGG line 2! * 1! * 3! == 12 2! * 1! * 3! == 12 2! * 1! * 3! == 12 permutations are generated.

To find the minimum number of pairwise exchanges:

 def minimal_number_of_swaps(a, b): """Find the minimal number of swaps to convert *a* into *b* sequence.""" return min(map(number_of_swaps, get_permutations(a, b))) 

Example:

 assert list(get_permutations('kamal', 'amalk')) == [(1,2,3,4,0), (3,2,1,4,0)] assert minimal_number_of_swaps('kamal', 'amalk') == 3 

Here, (1,2,3,4,0) permutation requires 4 pairwise exchanges to get (0,1,2,3,4) (single permutation), and (3,2,1,4,0) permutation requires only 3 :

 (3,2,1,4,0) -> # мСняСм 0,3 ΠΏΠ°Ρ€Ρƒ индСксов (0,2,1,4,3) -> # мСняСм 1,2 ΠΏΠ°Ρ€Ρƒ индСксов (0,1,2,4,3) -> # мСняСм 3,4 ΠΏΠ°Ρ€Ρƒ индСксов (0,1,2,3,4) 

The same permutation, but in the form of letters:

 01234 01243 02143 32140 kamal -> kamla -> kmala -> amalk 

still:

 yoda_words = "in the force strong you are".split() normal_words = "you are strong in the force".split() assert minimal_number_of_swaps(normal_words, yoda_words) == 5 

here the letters are whole words, and since all words are unique, one could use a simpler get_permutation() function, since only one permutation is possible. number_of_swaps(permutation) works by counting how many cycles are present in the permutation β€” the result is equal to len(permutation) - ncycles .

    1. Yes.

    2. The easiest option is to search through all possible permutations for those elements that stand in different places.

    • one
      Please try to write more detailed answers. I am sure the author of the question would be grateful for a detailed expert answer on the subject of the question. - Nicolas Chabanovsky ♦