Как вывести все перестановки строки
Перестановка — это расположение объектов в определённом порядке. Строку длины n можно переставить n! способами.
В этой статье показано, как найти все перестановки заданной строки с примерами на C++, Python, JavaScript и C. Код предназначен для демонстрации: вы можете подставить свои строки вместо примеров.
Как работают перестановки
Рассмотрим строку str = “MUO”. Требуется вывести все перестановки.
Пример 1: str = “MUO”
Перестановки “MUO”:
- “MUO”
- “MOU”
- “UMO”
- “UOM”
- “OUM”
- “OMU”
Пример 2: str = “AB”
Перестановки “AB”:
- “AB”
- “BA”
Если в строке есть повторяющиеся символы (например, “ABBA”), простые рекурсивные алгоритмы будут печатать дубликаты. Мы позже покажем, как этого избежать.
Важно: рост количества перестановок факториален — для n=10 это 3 628 800 перестановок. На практике это ограничивает применение полного перебора небольшими n.
C++ программа для вывода всех перестановок строки
Ниже — исходный C++ код, печатающий все перестановки рекурсивным обменом символов:
// C++ program to print all
// permutations of a string
#include
using namespace std;
// Function to print permutations of string
void findPermutations(string str, int leftIndex, int rightIndex)
{
if (leftIndex == rightIndex)
{
cout << str << endl;
}
else
{
for (int i = leftIndex; i <= rightIndex; i++)
{
swap(str[leftIndex], str[i]);
findPermutations(str, leftIndex+1, rightIndex);
//backtrack
swap(str[leftIndex], str[i]);
}
}
}
// Driver Code
int main()
{
string str1 = "MUO";
int size1 = str1.size();
cout << "str1: " << str1 << endl;
cout << "Permutations of " << str1 << ":" << endl;
findPermutations(str1, 0, size1-1);
string str2 = "AB";
int size2 = str2.size();
cout << "str2: " << str2 << endl;
cout << "Permutations of " << str2 << ":" << endl;
findPermutations(str2, 0, size2-1);
string str3 = "XYZ";
int size3 = str3.size();
cout << "str3: " << str3 << endl;
cout << "Permutations of " << str3 << ":" << endl;
findPermutations(str3, 0, size3-1);
return 0;
} Вывод программы:
str1: MUO
Permutations of MUO:
MUO
MOU
UMO
UOM
OUM
OMU
str2: AB
Permutations of AB:
AB
BA
str3: XYZ
Permutations of XYZ:
XYZ
XZY
YXZ
YZX
ZYX
ZXYPython программа для вывода всех перестановок строки
Пример на Python с рекурсивной перестановкой элементов списка:
# Python program to print all
# permutations of a string
def convertToString(List):
return ''.join(List)
# Function to print permutations of string
def findPermutations(s, leftIndex, rightIndex):
if leftIndex == rightIndex:
print(convertToString(s))
else:
for i in range(leftIndex, rightIndex+1):
s[leftIndex], s[i] = s[i], s[leftIndex]
findPermutations(s, leftIndex+1, rightIndex)
# backtrack
s[leftIndex], s[i] = s[i], s[leftIndex]
# Driver Code
str1 = "MUO"
size1 = len(str1)
s1 = list(str1)
print("str1:", str1)
print("Permutations of", str1,":")
findPermutations(s1, 0, size1-1)
str2 = "AB"
size2 = len(str2)
s2 = list(str2)
print("str2:", str2)
print("Permutations of", str2,":")
findPermutations(s2, 0, size2-1)
str3 = "XYZ"
size3 = len(str3)
s3 = list(str3)
print("str3:", str3)
print("Permutations of", str3,":")
findPermutations(s3, 0, size3-1)Вывод тот же, что и в C++ примере.
Совет: в реальных проектах на Python проще использовать itertools.permutations для генерации уникальных перестановок или всех перестановок с учётом повторений.
JavaScript программа для вывода всех перестановок строки
Пример на JavaScript, печать в документ (демонстрация):
// JavaScript program to print all
// permutations of a string
// Function to swap characters of the string
function swap(str, leftIndex, i) {
let temp;
let tempArray = str.split("");
temp = tempArray[leftIndex] ;
tempArray[leftIndex] = tempArray[i];
tempArray[i] = temp;
return (tempArray).join("");
}
// Function to print permutations of string
function findPermutations(str, leftIndex, rightIndex) {
if (leftIndex == rightIndex) {
document.write(str + "\n");
} else {
for (let i = leftIndex; i <= rightIndex; i++) {
str = swap(str, leftIndex, i);
findPermutations(str, leftIndex+1, rightIndex);
//backtrack
str = swap(str, leftIndex, i);;
}
}
}
// Driver Code
var str1 = "MUO";
var size1 = str1.length;
document.write("str1: " + str1 + "\n");
document.write("Permutations of " + str1 + ":" + "\n");
findPermutations(str1, 0, size1-1);
var str2 = "AB";
var size2 = str2.length;
document.write("str2: " + str2 + "\n");
document.write("Permutations of " + str2 + ":" + "\n");
findPermutations(str2, 0, size2-1);
var str3 = "XYZ";
var size3 = str3.length;
document.write("str3: " + str3 + "\n");
document.write("Permutations of " + str3 + ":" + "\n");
findPermutations(str3, 0, size3-1);Здесь полезно помнить про обход без дубликатов и про более эффективные алгоритмы для больших n.
C программа для вывода всех перестановок строки
C-реализация с обменом символов и рекурсией:
// C program to print all
// permutations of a string
#include
#include
// Function to swap characters of the string
void swap(char str[], int leftIndex, int i)
{
char temp = str[leftIndex];
str[leftIndex] = str[i];
str[i] = temp;
}
// Function to print permutations of string
void findPermutations(char str[], int leftIndex, int rightIndex)
{
if (leftIndex == rightIndex)
{
printf("%s \n", str);
}
else
{
for (int i = leftIndex; i <= rightIndex; i++)
{
swap(str, leftIndex, i);
findPermutations(str, leftIndex+1, rightIndex);
//backtrack
swap(str, leftIndex, i);
}
}
}
// Driver Code
int main()
{
char str1[] = "MUO";
int size1 = strlen(str1);
printf("str1: %s \n", str1);
printf("Permutations of %s: \n", str1);
findPermutations(str1, 0, size1-1);
char str2[] = "AB";
int size2 = strlen(str2);
printf("str2: %s \n", str2);
printf("Permutations of %s: \n", str2);
findPermutations(str2, 0, size2-1);
char str3[] = "XYZ";
int size3 = strlen(str3);
printf("str3: %s \n", str3);
printf("Permutations of %s: \n", str3);
findPermutations(str3, 0, size3-1);
return 0;
} Вывод совпадает с предыдущими примерами.
Альтернативные подходы и когда они лучше
- Использовать библиотечные функции: в C++ есть std::next_permutation, в Python — itertools.permutations. Подходы проще и часто быстрее в разработке.
- Heap’s algorithm — эффективен для генерации перестановок без лишних копирований; полезен при ограничениях по памяти.
- Итерирование по лексикографическому порядку (next_permutation) подходит, когда нужна сортированная выдача.
- Генерация без дубликатов: если вход содержит повторяющиеся символы, сортируйте и применяйте next_permutation или используйте set/просеивание, чтобы выводить только уникальные варианты.
Когда эти решения не подходят:
- Если n большой (обычно n>10), полный вывод всех перестановок непрактичен из-за факториального взрыва.
- Если нужна случайная перестановка без полного перечисления — используйте алгоритм Фишера–Йейтса.
Практические советы и эвристики
- Оцените n!: если n! превышает допустимое число операций/памяти, переключитесь на выборочные или вероятностные методы.
- Для уникальных перестановок сортируйте массив и применяйте next_permutation или фильтр на уровне вывода.
- Избегайте ненужных копий строки внутри рекурсии: в критичных по скорости реализациях меняйте символы in-place и затем возвращайте назад (backtrack).
- Для многопоточной генерации разбейте пространство перестановок по фиксированным префиксам.
Быстрая методология адаптации к проекту
- Определите максимальное n, с которым вы будете работать.
- Выберите стратегию: полная генерация, генерация уникальных, случайные перестановки.
- Если нужна полная генерация и n≤9, используйте рекурсию или next_permutation.
- Если есть повторяющиеся символы, примените сортировку + фильтр или структуры данных для уникальности.
- Напишите тесты и определите ограничения по времени/памяти.
Критерии приёмки
- Алгоритм корректно печатает все перестановки для строк без повторов.
- При строках с повторяющимися символами — поведение согласовано с требованиями (печать дубликатов или только уникальных).
- Время выполнения и использование памяти соответствуют заданным ограничениям проекта.
Факт-бокс: рост сложности
- n = 5 → 120 перестановок
- n = 8 → 40 320 перестановок
- n = 10 → 3 628 800 перестановок
Фактор роста — факториал n (n!). Это ключевой фактор при принятии решения о полном перечислении.
Ролевые чек-листы
Для разработчика: проверить корректность обменов и возврат состояний (backtrack).
Для тестировщика: составить набор тестов с повторяющимися символами, пустой строкой и короткими/длинными входами.
Для архитектора: оценить, возможно ли использовать библиотечные методы или требуется кастомизация ради производительности.
Итог
Вы узнали, как рекурсивно генерировать все перестановки строки на C++, Python, JavaScript и C. Для практических задач выбирайте библиотечные функции или оптимальные алгоритмы (Heap, next_permutation), избегайте полного перечисления при больших n и используйте фильтры для удаления дубликатов.
Важно: перестановки растут факториально, поэтому всегда проверяйте ограничения по n и оценивайте альтернативные подходы.