Сгенерировать список всех возможных перестановок строки
Как бы я начал генерировать список всех возможных перестановок строки между символами x и y в длину, содержащий переменный список символов.
Любой язык будет работать, но он должен быть переносимым.
- Вычислить наибольший прямоугольник во вращающемся прямоугольнике
- Алгоритм для выделения перекрывающихся прямоугольников?
- Существует ли алгоритм сортировки по целому числу O (n)?
- Что такое инъекция зависимости?
- Для чего нужен пузырь?
- Лучший способ найти точку на круге, ближайшем к данной точке
- Болт-коллаж - обнаружение и обработка
- Что такое самоуверенное программное обеспечение?
- Линия пересечения двух плоскостей
- Что такое оптимизация хвостового звонка?
- Сбита ли математика с плавающей запятой?
- Что такое композиция, относящаяся к объектно-ориентированному дизайну?
- Уравнение для тестирования, если точка находится внутри круга
Есть несколько способов сделать это. Общие методы используют рекурсию, память или динамическое программирование. Основная идея заключается в том, что вы создаете список всех строк длины 1, а затем на каждой итерации для всех строк, созданных в последней итерации, добавляете эту строку, конкатенированную с каждым символом в строке отдельно. (индекс переменной в приведенном ниже коде отслеживает начало последней и следующей итерации)
Некоторые псевдокоды:
list = originalString.split('') index = (0,0) list = [""] for iteration n in 1 to y: index = (index[1], len(list)) for string s in list.subset(index[0] to end): for character c in originalString: list.add(s + c)
вам нужно будет удалить все строки меньше, чем x, они будут первыми (x-1) * len (originalString) в списке.
Лучше использовать backtracking
#include #include void swap(char *a, char *b) { char temp; temp = *a; *a = *b; *b = temp; } void print(char *a, int i, int n) { int j; if(i == n) { printf("%s\n", a); } else { for(j = i; j <= n; j++) { swap(a + i, a + j); print(a, i + 1, n); swap(a + i, a + j); } } } int main(void) { char a[100]; gets(a); print(a, 0, strlen(a) - 1); return 0; }
Вы получите много строк, это точно …
\ sum_ {i = x} ^ y {\ frac {r!} {{(ri)}!}} http://www.codecogs.com/eq.latex?%5Csum_%7Bi=x%7D%5Ey% 20% 7B% 20% 5Cfrac% 7BR!% 7D% 7B% 7B (г)% 7D!% 7D% 20% 7D
Где, x и y – это то, как вы их определяете, а r – количество символов, которые мы выбираем, – если я правильно вас понимаю. Вы должны обязательно генерировать их по мере необходимости и не становиться неаккуратными и говорить, генерировать силовую установку и затем фильтровать длину строк.
Следующие, безусловно, не лучший способ их генерировать, но это интересно в стороне, тем не менее.
Кнут (том 4, пучок 2, 7.2.1.3) говорит нам, что (s, t) -комбинация эквивалентна s + 1 вещам, принятым t за раз с повторением – an (s, t) -комбинация – это обозначения, используемые Knuth, равный {t \ выберите {s + t} http://www.codecogs.com/eq.latex?%7Bt%20%5Cchoose%20%7Bs+t%7D%7D . Мы можем это понять, сначала генерируя каждую (s, t) -комбинацию в двоичной форме (так, длины (s + t)) и подсчитывая число 0 слева от каждого 1.
10001000011101 -> становится перестановкой: {0, 3, 4, 4, 4, 1}
Нерекурсивное решение согласно Кнуту, пример Python:
def nextPermutation(perm): k0 = None for i in range(len(perm)-1): if perm[i]
Вы можете взглянуть на « Эффективное перечисление подмножеств набора », в котором описывается алгоритм для части того, что вы хотите – быстро сгенерируйте все подмножества из N символов от длины x до y. Он содержит реализацию в C.
Для каждого подмножества вам все равно придется генерировать все перестановки. Например, если вам нужно 3 символа из «abcde», этот алгоритм даст вам «abc», «abd», «abe» … но вам придется переставлять каждый из них, чтобы получить «acb», «bac», «bca» и т. д.
Некоторые рабочие Java-коды основаны на ответе Сарпа :
public class permute { static void permute(int level, String permuted, boolean used[], String original) { int length = original.length(); if (level == length) { System.out.println(permuted); } else { for (int i = 0; i < length; i++) { if (!used[i]) { used[i] = true; permute(level + 1, permuted + original.charAt(i), used, original); used[i] = false; } } } } public static void main(String[] args) { String s = "hello"; boolean used[] = {false, false, false, false, false}; permute(0, "", used, s); } }
Вот простое решение в C #.
Он генерирует только отдельные перестановки данной строки.
static public IEnumerable permute(string word) { if (word.Length > 1) { char character = word[0]; foreach (string subPermute in permute(word.Substring(1))) { for (int index = 0; index <= subPermute.Length; index++) { string pre = subPermute.Substring(0, index); string post = subPermute.Substring(index); if (post.Contains(character)) continue; yield return pre + character + post; } } } else { yield return word; } }
Здесь есть много хороших ответов. Я также предлагаю очень простое рекурсивное решение на C ++.
#include #include template void permutations(std::string s, Consume consume, std::size_t start = 0) { if (start == s.length()) consume(s); for (std::size_t i = start; i < s.length(); i++) { std::swap(s[start], s[i]); permutations(s, consume, start + 1); } } int main(void) { std::string s = "abcd"; permutations(s, [](std::string s) { std::cout << s << std::endl; }); }
Примечание : строки с повторяющимися символами не будут создавать уникальные перестановки.
Я просто взбивал это быстро в Ruby:
def perms(x, y, possible_characters) all = [""] current_array = all.clone 1.upto(y) { |iteration| next_array = [] current_array.each { |string| possible_characters.each { |c| value = string + c next_array.insert next_array.length, value all.insert all.length, value } } current_array = next_array } all.delete_if { |string| string.length < x } end
Вы можете заглянуть в язык API для встроенных функций типа перестановок, и вы можете написать более оптимизированный код, но если цифры будут такими высокими, я не уверен, что есть много способов получить много результатов ,
В любом случае идея кода начинается с строки длиной 0, а затем отслеживает все строки длины Z, где Z - текущий размер итерации. Затем пройдите через каждую строку и добавьте каждый символ в каждую строку. Наконец, в конце, удалите все, которые были ниже порогового значения x, и верните результат.
Я не тестировал его с потенциально бессмысленным вводом (список нулевых символов, странные значения x и y и т. Д.).
Это перевод версии Ruby от Mike, в Common Lisp:
(defun perms (xy original-string) (loop with all = (list "") with current-array = (list "") for iteration from 1 to y do (loop with next-array = nil for string in current-array do (loop for c across original-string for value = (concatenate 'string string (string c)) do (push value next-array) (push value all)) (setf current-array (reverse next-array))) finally (return (nreverse (delete-if #'(lambda (el) (< (length el) x)) all)))))
И еще одна версия, немного короче и использующая больше возможностей контура:
(defun perms (xy original-string) (loop repeat y collect (loop for string in (or (car (last sets)) (list "")) append (loop for c across original-string collect (concatenate 'string string (string c)))) into sets finally (return (loop for set in sets append (loop for el in set when (>= (length el) x) collect el)))))
Вот простое рекурсивное решение C #:
Метод:
public ArrayList CalculateWordPermutations(string[] letters, ArrayList words, int index) { bool finished = true; ArrayList newWords = new ArrayList(); if (words.Count == 0) { foreach (string letter in letters) { words.Add(letter); } } for(int j=index; j
Вызов:
string[] letters = new string[]{"a","b","c"}; ArrayList words = CalculateWordPermutations(letters, new ArrayList(), 0);
В Perl, если вы хотите ограничить себя строчным алфавитом, вы можете сделать это:
my @result = ("a" .. "zzzz");
Это дает все возможные строки от 1 до 4 символов с использованием строчных символов. Для прописных букв измените "a"
на "A"
и "zzzz"
на "ZZZZ"
.
Для смешанного случая он становится намного сложнее и, вероятно, не справляется с одним из встроенных операторов Perl.
… и вот версия C:
void permute(const char *s, char *out, int *used, int len, int lev) { if (len == lev) { out[lev] = '\0'; puts(out); return; } int i; for (i = 0; i < len; ++i) { if (! used[i]) continue; used[i] = 1; out[lev] = s[i]; permute(s, out, used, len, lev + 1); used[i] = 0; } return; }
(ABC) -> A.perm (BC) -> A.perm [B.perm (C)] -> A.perm [( * B C), (C B * )] -> [( * A BC ), (B A C), (BC A * ), ( * A CB), (C A B), (CB A * )] Чтобы удалить дубликаты при вставке каждой проверки алфавита, чтобы увидеть, заканчивается ли предыдущая строка с тем же алфавитом (почему? – упражнение)
public static void main(String[] args) { for (String str : permStr("ABBB")){ System.out.println(str); } } static Vector permStr(String str){ if (str.length() == 1){ Vector ret = new Vector (); ret.add(str); return ret; } char start = str.charAt(0); Vector endStrs = permStr(str.substring(1)); Vector newEndStrs = new Vector (); for (String endStr : endStrs){ for (int j = 0; j <= endStr.length(); j++){ if (endStr.substring(0, j).endsWith(String.valueOf(start))) break; newEndStrs.add(endStr.substring(0, j) + String.valueOf(start) + endStr.substring(j)); } } return newEndStrs; }
Печать всех перестановок без дубликатов
Ruby ответ, который работает:
class String def each_char_with_index 0.upto(size - 1) do |index| yield(self[index..index], index) end end def remove_char_at(index) return self[1..-1] if index == 0 self[0..(index-1)] + self[(index+1)..-1] end end def permute(str, prefix = '') if str.size == 0 puts prefix return end str.each_char_with_index do |char, index| permute(str.remove_char_at(index), prefix + char) end end # example # permute("abc")
Рекурсивное решение в C ++
int main (int argc, char * const argv[]) { string s = "sarp"; bool used [4]; permute(0, "", used, s); } void permute(int level, string permuted, bool used [], string &original) { int length = original.length(); if(level == length) { // permutation complete, display cout << permuted << endl; } else { for(int i=0; i
Следующая recursion Java печатает все перестановки заданной строки:
//call it as permut("",str); public void permut(String str1,String str2){ if(str2.length() != 0){ char ch = str2.charAt(0); for(int i = 0; i <= str1.length();i++) permut(str1.substring(0,i) + ch + str1.substring(i,str1.length()), str2.substring(1,str2.length())); }else{ System.out.println(str1); } }
Ниже приведена обновленная версия вышеперечисленного метода «перестановки», которая делает n! (n факториал) менее рекурсивных вызовов по сравнению с указанным выше методом
//call it as permut("",str); public void permut(String str1,String str2){ if(str2.length() > 1){ char ch = str2.charAt(0); for(int i = 0; i <= str1.length();i++) permut(str1.substring(0,i) + ch + str1.substring(i,str1.length()), str2.substring(1,str2.length())); }else{ char ch = str2.charAt(0); for(int i = 0; i <= str1.length();i++) System.out.println(str1.substring(0,i) + ch + str1.substring(i,str1.length()), str2.substring(1,str2.length())); } }
Я не уверен, почему вы хотели бы сделать это в первую очередь. Полученный набор для любых умеренно больших значений x и y будет огромным и будет экспоненциально расти, так как x и / или y будут больше.
Допустим, что ваш набор возможных символов – это 26 строчных букв алфавита, и вы попросите свое приложение сгенерировать все перестановки, где длина = 5. Предполагая, что вы не исчерпали память, вы получите 11 881 376 (т.е. 26 на мощность из 5). Увеличьте эту длину до 6, и вы получите 308 915 776 строк назад. Эти цифры очень болезненны, очень быстро.
Вот решение, которое я собрал в Java. Вам нужно предоставить два аргумента времени выполнения (соответствующие x и y). Повеселись.
public class GeneratePermutations { public static void main(String[] args) { int lower = Integer.parseInt(args[0]); int upper = Integer.parseInt(args[1]); if (upper < lower || upper == 0 || lower == 0) { System.exit(0); } for (int length = lower; length <= upper; length++) { generate(length, ""); } } private static void generate(int length, String partial) { if (length <= 0) { System.out.println(partial); } else { for (char c = 'a'; c <= 'z'; c++) { generate(length - 1, partial + c); } } } }
import java.util.*; public class all_subsets { public static void main(String[] args) { String a = "abcd"; for(String s: all_perm(a)) { System.out.println(s); } } public static Set concat(String c, Set lst) { HashSet ret_set = new HashSet (); for(String s: lst) { ret_set.add(c+s); } return ret_set; } public static HashSet all_perm(String a) { HashSet set = new HashSet (); if(a.length() == 1) { set.add(a); } else { for(int i=0; i
Вот нерекурсивная версия, с которой я столкнулся, в javascript. Это не основано на нерекурсивном надписи Кнута выше, хотя оно имеет некоторые сходства в элементарной свопинге. Я проверил его правильность для входных массивов до 8 элементов.
Быстрая оптимизация была бы предварительным вылетом массива и избежанием push()
.
Основная идея:
-
Для одного исходного массива создайте первый новый набор массивов, которые поочередно меняют первый элемент с каждым последующим элементом, каждый раз оставляя остальные элементы невозмутимыми. например: с учетом 1234, генерировать 1234, 2134, 3214, 4231.
-
Используйте каждый массив из предыдущего прохода в качестве семени для нового прохода, но вместо замены первого элемента замените второй элемент на каждый последующий элемент. Кроме того, на этот раз не включайте исходный массив в выходной файл.
-
Повторите шаг 2 до завершения.
Вот пример кода:
function oxe_perm(src, depth, index) { var perm = src.slice(); // duplicates src. perm = perm.split(""); perm[depth] = src[index]; perm[index] = src[depth]; perm = perm.join(""); return perm; } function oxe_permutations(src) { out = new Array(); out.push(src); for (depth = 0; depth < src.length; depth++) { var numInPreviousPass = out.length; for (var m = 0; m < numInPreviousPass; ++m) { for (var n = depth + 1; n < src.length; ++n) { out.push(oxe_perm(out[m], depth, n)); } } } return out; }
Я нуждался в этом сегодня, и хотя ответы, которые уже дали мне, указали мне в правильном направлении, они не совсем то, что я хотел.
Вот реализация с использованием метода кучи. Длина массива должна быть не менее 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
Другие методы описаны различными авторами. Кнут описывает два, один дает лексический порядок, но является сложным и медленным, другой известен как метод простых изменений. Цзе Гао и Дианджун Ван также написал интересную статью.
В rubyе:
str = "a" 100_000_000.times {puts str.next!}
Это довольно быстро, но это займет некоторое время =). Конечно, вы можете начать с «aaaaaaaa», если короткие строки вам не интересны.
Возможно, я неверно истолковал фактический вопрос – на одной из сообщений это звучало так, как будто вам просто нужна была строка с строкой strutforce, но в основном вопросе кажется, что вам нужно переставить определенную строку.
Ваша проблема несколько похожа на эту: http://beust.com/weblog/archives/000491.html (список всех целых чисел, в которых ни одна из цифр не повторяется, что привело к большому количеству языков, разрешающих ее, с ocaml guy, используя перестановки, и некоторый java-парень, использующий еще одно решение).
Этот код в python при вызове с allowed_characters
установленными на [0,1]
и 4 символа max, будет генерировать 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()
Надеюсь, это вам полезно. Работает с любым персонажем, а не только с числами
Вот ссылка, которая описывает, как печатать перестановки строки. http://nipun-linuxtips.blogspot.in/2012/11/print-all-permutations-of-characters-in.html
Хотя это точно не отвечает на ваш вопрос, вот один из способов генерации каждой перестановки букв из нескольких строк одинаковой длины: например, если ваши слова были «кофе», «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) !
Если количество комбинаций является чрезмерным, вы можете разбить его на ряд меньших слов и объединить их в конце.
c # итеративный:
public List Permutations(char[] chars) { List words = new List (); words.Add(chars[0].ToString()); for (int i = 1; i < chars.Length; ++i) { int currLen = words.Count; for (int j = 0; j < currLen; ++j) { var w = words[j]; for (int k = 0; k <= w.Length; ++k) { var nstr = w.Insert(k, chars[i].ToString()); if (k == 0) words[j] = nstr; else words.Add(nstr); } } } return words; }
Существует итеративная реализация Java в UncommonsMaths (работает для списка объектов):
/** * Generate the indices into the elements array for the next permutation. The * algorithm is from Kenneth H. Rosen, Discrete Mathematics and its * Applications, 2nd edition (NY: McGraw-Hill, 1991), p. 284) */ private void generateNextPermutationIndices() { if (remainingPermutations == 0) { throw new IllegalStateException("There are no permutations " + "remaining. Generator must be reset to continue using."); } else if (remainingPermutations < totalPermutations) { // Find largest index j with // permutationIndices[j] < permutationIndices[j + 1] int j = permutationIndices.length - 2; while (permutationIndices[j] > permutationIndices[j + 1]) { j--; } // Find index k such that permutationIndices[k] is smallest integer // greater than permutationIndices[j] to the right // of permutationIndices[j]. int k = permutationIndices.length - 1; while (permutationIndices[j] > permutationIndices[k]) { k--; } // Interchange permutation indices. int temp = permutationIndices[k]; permutationIndices[k] = permutationIndices[j]; permutationIndices[j] = temp; // Put tail end of permutation after jth position in increasing order. int r = permutationIndices.length - 1; int s = j + 1; while (r > s) { temp = permutationIndices[s]; permutationIndices[s] = permutationIndices[r]; permutationIndices[r] = temp; r--; s++; } } --remainingPermutations; } /** * Generate the next permutation and return a list containing * the elements in the appropriate order. This overloaded method * allows the caller to provide a list that will be used and returned. * The purpose of this is to improve performance when iterating over * permutations. If the {@link #nextPermutationAsList()} method is * used it will create a new list every time. When iterating over * permutations this will result in lots of short-lived objects that * have to be garbage collected. This method allows a single list * instance to be reused in such circumstances. * @param destination Provides a list to use to create the * permutation. This is the list that will be returned, once * it has been filled with the elements in the appropriate order. * @return The next permutation as a list. */ public List nextPermutationAsList(List destination) { generateNextPermutationIndices(); // Generate actual permutation. destination.clear(); for (int i : permutationIndices) { destination.add(elements[i]); } return destination; }
Полный источник
def gen( x,y,list): #to generate all strings inserting y at different positions list = [] list.append( y+x ) for i in range( len(x) ): list.append( func(x,0,i) + y + func(x,i+1,len(x)-1) ) return list def func( x,i,j ): #returns x[i..j] z = '' for i in range(i,j+1): z = z+x[i] return z def perm( x , length , list ): #perm function if length == 1 : # base case list.append( x[len(x)-1] ) return list else: lists = perm( x , length-1 ,list ) lists_temp = lists #temporarily storing the list lists = [] for i in range( len(lists_temp) ) : list_temp = gen(lists_temp[i],x[length-2],lists) lists += list_temp return lists
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
максимальные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
Вот мой вопрос о нерекурсивной версии
Питоновское решение:
from itertools import permutations s = 'ABCDEF' p = [''.join(x) for x in permutations(s)]