Создать список всех возможных перестановок строки - PullRequest
153 голосов
/ 02 августа 2008

Как мне создать список всех возможных перестановок строки длиной от x до y символов, содержащий список переменных символов.

Любой язык будет работать, но он должен быть переносимым.

Ответы [ 35 ]

3 голосов
/ 02 октября 2011

Мне это нужно было сегодня, и хотя уже приведенные ответы указали мне правильное направление, они не совсем то, что я хотел.

Вот реализация, использующая метод Heap. Длина массива должна быть не менее 3, а по практическим соображениям - не более 10 или около того, в зависимости от того, что вы хотите сделать, терпения и тактовой частоты.

Перед входом в цикл инициализируйте Perm(1 To N) с первой перестановкой, Stack(3 To N) с нулями * и Level с 2**. В конце цикла вызовите NextPerm, который вернет false, когда мы закончим.

* VB сделает это за вас.

** Вы можете немного изменить NextPerm, чтобы сделать это ненужным, но это более понятно.

Option Explicit

Function NextPerm(Perm() As Long, Stack() As Long, Level As Long) As Boolean
Dim N As Long
If Level = 2 Then
    Swap Perm(1), Perm(2)
    Level = 3
Else
    While Stack(Level) = Level - 1
        Stack(Level) = 0
        If Level = UBound(Stack) Then Exit Function
        Level = Level + 1
    Wend
    Stack(Level) = Stack(Level) + 1
    If Level And 1 Then N = 1 Else N = Stack(Level)
    Swap Perm(N), Perm(Level)
    Level = 2
End If
NextPerm = True
End Function

Sub Swap(A As Long, B As Long)
A = A Xor B
B = A Xor B
A = A Xor B
End Sub

'This is just for testing.
Private Sub Form_Paint()
Const Max = 8
Dim A(1 To Max) As Long, I As Long
Dim S(3 To Max) As Long, J As Long
Dim Test As New Collection, T As String
For I = 1 To UBound(A)
    A(I) = I
Next
Cls
ScaleLeft = 0
J = 2
Do
    If CurrentY + TextHeight("0") > ScaleHeight Then
        ScaleLeft = ScaleLeft - TextWidth(" 0 ") * (UBound(A) + 1)
        CurrentY = 0
        CurrentX = 0
    End If
    T = vbNullString
    For I = 1 To UBound(A)
        Print A(I);
        T = T & Hex(A(I))
    Next
    Print
    Test.Add Null, T
Loop While NextPerm(A, S, J)
J = 1
For I = 2 To UBound(A)
    J = J * I
Next
If J <> Test.Count Then Stop
End Sub

Другие методы описаны различными авторами. Кнут описывает два, один дает лексический порядок, но сложен и медленен, другой известен как метод простых изменений. Цзе Гао и Дяньцзюнь Ван также написали интересную статью.

2 голосов
/ 15 сентября 2008

В рубине:

str = "a"
100_000_000.times {puts str.next!}

Это довольно быстро, но это займет некоторое время =). Конечно, вы можете начать с "aaaaaaaa", если короткие строки вам не интересны.

Хотя, возможно, я неверно истолковал реальный вопрос - в одном из постов он звучал так, как будто вам просто нужна библиотека строк bruteforce, но в основном вопрос звучит так, как будто вам нужно переставить определенную строку.

Ваша проблема в чем-то похожа на эту: http://beust.com/weblog/archives/000491.html (перечислите все целые числа, в которых ни одна из цифр не повторяется, что привело к ее решению на многих языках, когда парень из ocaml использует перестановки, какой-то парень из Java, использующий еще одно решение).

2 голосов
/ 26 мая 2011

Этот код в python, когда вызывается с allowed_characters, установленным на [0,1] и максимум 4 символа, генерирует 2 ^ 4 результата:

['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']

def generate_permutations(chars = 4) :

#modify if in need!
    allowed_chars = [
        '0',
        '1',
    ]

    status = []
    for tmp in range(chars) :
        status.append(0)

    last_char = len(allowed_chars)

    rows = []
    for x in xrange(last_char ** chars) :
        rows.append("")
        for y in range(chars - 1 , -1, -1) :
            key = status[y]
            rows[x] = allowed_chars[key] + rows[x]

        for pos in range(chars - 1, -1, -1) :
            if(status[pos] == last_char - 1) :
                status[pos] = 0
            else :
                status[pos] += 1
                break;

    return rows

import sys


print generate_permutations()

Надеюсь, это вам пригодится. Работает с любым символом, а не только с цифрами

2 голосов
/ 14 февраля 2014

Вот ссылка, которая описывает, как напечатать перестановки строки. http://nipun -linuxtips.blogspot.in / 2012/11 / печать-все-перестановками-из-символов-in.html

0 голосов
/ 06 февраля 2017

Возможные перестановки строк могут быть вычислены с использованием рекурсивной функции. Ниже приведено одно из возможных решений.

public static String insertCharAt(String s, int index, char c) {
        StringBuffer sb = new StringBuffer(s);
        StringBuffer sbb = sb.insert(index, c);
        return sbb.toString();
}

public static ArrayList<String> getPerm(String s, int index) {
        ArrayList<String> perm = new ArrayList<String>();

        if (index == s.length()-1) {
            perm.add(String.valueOf(s.charAt(index)));
            return perm;
        }

        ArrayList<String> p = getPerm(s, index+1);
        char c = s.charAt(index);

        for(String pp : p) {
            for (int idx=0; idx<pp.length()+1; idx++) {
                String ss = insertCharAt(pp, idx, c);
                perm.add(ss);
            }
        }

        return perm;    
}

public static void testGetPerm(String s) {
        ArrayList<String> perm = getPerm(s,0);
        System.out.println(s+" --> total permutation are :: "+perm.size());
        System.out.println(perm.toString());
}
0 голосов
/ 05 июня 2016

код написан для языка Java:

пакет namo.algorithms;

импорт java.util.Scanner;

публичный класс Перестановки {

public static int totalPermutationsCount = 0;
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        System.out.println("input string : ");
        String inputString = sc.nextLine();
        System.out.println("given input String ==> "+inputString+ " :: length is = "+inputString.length());
        findPermuationsOfString(-1, inputString);
        System.out.println("**************************************");
        System.out.println("total permutation strings ==> "+totalPermutationsCount);
    }


    public  static void findPermuationsOfString(int fixedIndex, String inputString) {
        int currentIndex = fixedIndex +1;

        for (int i = currentIndex; i < inputString.length(); i++) {
            //swap elements and call the findPermuationsOfString()

            char[] carr = inputString.toCharArray();
            char tmp = carr[currentIndex];
            carr[currentIndex] = carr[i];
            carr[i] = tmp;
            inputString =  new String(carr);

            //System.out.println("chat At : current String ==> "+inputString.charAt(currentIndex));
            if(currentIndex == inputString.length()-1) {
                totalPermutationsCount++;
                System.out.println("permuation string ==> "+inputString);
            } else {
                //System.out.println("in else block>>>>");
                findPermuationsOfString(currentIndex, inputString);
                 char[] rarr = inputString.toCharArray();
                    char rtmp = carr[i];
                    carr[i] = carr[currentIndex];
                    carr[currentIndex] = rtmp;
                    inputString =  new String(carr);
            }
        }
    }

}

0 голосов
/ 27 июня 2015

Хорошо, вот элегантное, нерекурсивное, O (n!) Решение:

public static StringBuilder[] permutations(String s) {
        if (s.length() == 0)
            return null;
        int length = fact(s.length());
        StringBuilder[] sb = new StringBuilder[length];
        for (int i = 0; i < length; i++) {
            sb[i] = new StringBuilder();
        }
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            int times = length / (i + 1);
            for (int j = 0; j < times; j++) {
                for (int k = 0; k < length / times; k++) {
                    sb[j * length / times + k].insert(k, ch);
                }
            }
        }
        return sb;
    }
0 голосов
/ 13 июля 2014

Питонический раствор:

from itertools import permutations
s = 'ABCDEF'
p = [''.join(x) for x in permutations(s)]
0 голосов
/ 16 сентября 2008

Хотя это не дает точного ответа на ваш вопрос, вот один из способов генерировать каждую перестановку букв из ряда строк одинаковой длины: например, если ваши слова были «coffee», «joomla» и «moodle» , вы можете ожидать вывод типа "coodle", "joodee", "joffle" и т. д.

По сути, количество комбинаций - это (количество слов) в степени (количество букв на слово). Таким образом, выберите случайное число от 0 до количества комбинаций - 1, преобразуйте это число в основание (количество слов), а затем используйте каждую цифру этого числа в качестве индикатора, для которого нужно взять следующую букву.

Например: в приведенном выше примере. 3 слова, 6 букв = 729 комбинаций. Выберите случайное число: 465. Преобразуйте в основание 3: 122020. Возьмите первую букву из слова 1, 2-ю из слова 2, 3-ю из слова 2, 4-ю из слова 0 ... и вы получите ... "joofle".

Если вам нужны все перестановки, просто зацикливайтесь от 0 до 728. Конечно, если вы выбираете одно случайное значение, гораздо более простой менее запутанный способ будет заключаться в переборе букв , Этот метод позволяет вам избежать рекурсии, если вам нужны все перестановки, плюс он заставляет вас выглядеть так, будто вы знаете Maths (tm) !

Если количество комбинаций чрезмерно, вы можете разбить его на серию более мелких слов и объединить их в конце.

0 голосов
/ 23 января 2014
def permutation(str)
  posibilities = []
  str.split('').each do |char|
    if posibilities.size == 0
      posibilities[0] = char.downcase
      posibilities[1] = char.upcase
    else
      posibilities_count = posibilities.length
      posibilities = posibilities + posibilities
      posibilities_count.times do |i|
        posibilities[i] += char.downcase
        posibilities[i+posibilities_count] += char.upcase
      end
    end
  end
  posibilities
end

Вот мой взгляд на нерекурсивную версию

...