N個の要素のリストがあるとします。n個あることはわかっています。これらの要素を並べる可能な方法。このリストのすべての可能な順序を生成するアルゴリズムとは何ですか?例、リスト[a、b、c]があります。アルゴリズムは[[a、b、c]、[a、c、b、]、[b、a、c]、[b、c、a]、[c、a、b]、[c、b 、a]]。
ここでこれを読んでいます http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations
しかし、ウィキペディアは説明が上手ではありませんでした。私はそれの多くを理解していません。
基本的に、左から右への各アイテムに対して、残りのアイテムのすべての順列が生成されます(そして、それぞれに現在の要素が追加されます)。これは、最後のアイテムに到達するまで再帰的に(または痛みが好きな場合は繰り返し)、その時点で可能な順序は1つだけです。
したがって、リスト[1,2,3,4]を使用すると、1で始まるすべての順列が生成され、次に2で始まり、3、次に4の順列がすべて生成されます。
これにより、4つのアイテムのリストから3つのアイテムのリストへの順列を見つけることから生じる問題を効果的に軽減できます。 2つ、次に1つのアイテムリストに減らすと、すべてのアイテムリストが見つかります。
3色のボールを使用したプロセス順列の例:
(from https://en.wikipedia.org/wiki/Permutation#/media/File:Permutations_RGB.svg - https://commons.wikimedia.org/wiki /File:Permutations_RGB.svg )
配列上の所定の場所で機能するPythonのアルゴリズムを次に示します。
def permute(xs, low=0):
if low + 1 >= len(xs):
yield xs
else:
for p in permute(xs, low + 1):
yield p
for i in range(low + 1, len(xs)):
xs[low], xs[i] = xs[i], xs[low]
for p in permute(xs, low + 1):
yield p
xs[low], xs[i] = xs[i], xs[low]
for p in permute([1, 2, 3, 4]):
print p
ここで自分でコードを試すことができます: http://repl.it/J9v
ここにはすでに多くの優れたソリューションがありますが、この問題を自分でどのように解決したかを共有したいと思います。
問題について熟考した後、次の2つの結論を導き出しました。
L
のリストn
の場合、Lで始まるソリューションの数は等しくなります1、L2 ... Ln リストの要素。合計でサイズのリストのn!
順列n
があるため、各グループでn! / n = (n-1)!
順列を取得します。[a,b]
と[b,a]
のみがあります。これら2つのシンプルなアイデアを使用して、次のアルゴリズムを導き出しました。
permute array
if array is of size 2
return first and second element as new array
return second and first element as new array
else
for each element in array
new subarray = array with excluded element
return element + permute subarray
C#でこれを実装する方法は次のとおりです。
public IEnumerable<List<T>> Permutate<T>(List<T> input)
{
if (input.Count == 2) // this are permutations of array of size 2
{
yield return new List<T>(input);
yield return new List<T> {input[1], input[0]};
}
else
{
foreach(T elem in input) // going through array
{
var rlist = new List<T>(input); // creating subarray = array
rlist.Remove(elem); // removing element
foreach(List<T> retlist in Permutate(rlist))
{
retlist.Insert(0,elem); // inserting the element at pos 0
yield return retlist;
}
}
}
}
「辞書編集順序」に対するウィキペディアの答えは、料理本のスタイルでは完全に明白なようです。アルゴリズムの14世紀の起源を引用しています!
チェックとしてWikipediaのアルゴリズムのJavaで簡単な実装を作成しましたが、問題ありませんでした。しかし、例としてQにあるのは「すべての順列のリスト」ではなく、「すべての順列のリスト」なので、ウィキペディアはあまり役に立ちません。順列のリストを実行可能に構築する言語が必要です。そして、私を信じて、数十億の長さのリストは通常、命令型言語では扱われません。あなたは本当に、リストを第一級のオブジェクトとする非厳密な関数型プログラミング言語が欲しいのですが、宇宙の熱死にマシンを近づけないで物を取り出すことができます。
簡単だ。標準のHaskellまたは最新のFP言語:
-- perms of a list
perms :: [a] -> [ [a] ]
perms (a:as) = [bs ++ a:cs | perm <- perms as, (bs,cs) <- splits perm]
perms [] = [ [] ]
そして
-- ways of splitting a list into two parts
splits :: [a] -> [ ([a],[a]) ]
splits [] = [ ([],[]) ]
splits (a:as) = ([],a:as) : [(a:bs,cs) | (bs,cs) <- splits as]
WhirlWindが言ったように、あなたは最初から始めます。
カーソル自体を含む残りの各値とカーソルを交換します。これらはすべて新しいインスタンスです(例ではint[]
とarray.clone()
を使用しました)。
次に、これらすべての異なるリストで順列を実行し、カーソルが1つ右であることを確認します。
残りの値がなくなったら(カーソルは最後にあります)、リストを印刷します。これが停止条件です。
public void permutate(int[] list, int pointer) {
if (pointer == list.length) {
//stop-condition: print or process number
return;
}
for (int i = pointer; i < list.length; i++) {
int[] permutation = (int[])list.clone();.
permutation[pointer] = list[i];
permutation[i] = list[pointer];
permutate(permutation, pointer + 1);
}
}
再帰は常に維持するために精神的な努力が必要です。そして、大きな数の場合、階乗は簡単に巨大になり、スタックオーバーフローは簡単に問題になります。
小さい数値(3または4で、ほとんどが発生します)の場合、複数のループは非常に単純で単純です。ループでの回答が投票されなかったのは残念です。
(順列ではなく)列挙から始めましょう。コードを疑似Perlコードとして読むだけです。
$foreach $i1 in @list
$foreach $i2 in @list
$foreach $i3 in @list
print "$i1, $i2, $i3\n"
列挙は置換よりも頻繁に発生しますが、置換が必要な場合は、条件を追加するだけです。
$foreach $i1 in @list
$foreach $i2 in @list
$if $i2==$i1
next
$foreach $i3 in @list
$if $i3==$i1 or $i3==$i2
next
print "$i1, $i2, $i3\n"
大きなリストに対して一般的なメソッドが必要になる可能性がある場合は、基数メソッドを使用できます。最初に、列挙の問題を検討します。
$n=@list
my @radix
$for $i=0:$n
$radix[$i]=0
$while 1
my @temp
$for $i=0:$n
Push @temp, $list[$radix[$i]]
print join(", ", @temp), "\n"
$call radix_increment
subcode: radix_increment
$i=0
$while 1
$radix[$i]++
$if $radix[$i]==$n
$radix[$i]=0
$i++
$else
last
$if $i>=$n
last
基数の増分は、基本的に(リスト要素の数の基数における)カウントです。
置換が必要な場合は、ループ内にチェックを追加するだけです。
subcode: check_permutation
my @check
my $flag_dup=0
$for $i=0:$n
$check[$radix[$i]]++
$if $check[$radix[$i]]>1
$flag_dup=1
last
$if $flag_dup
next
編集:上記のコードは動作するはずですが、置換のために、radix_incrementは無駄になる可能性があります。したがって、時間が実際的な懸念事項である場合、radix_incrementをpermute_incに変更する必要があります。
subcode: permute_init
$for $i=0:$n
$radix[$i]=$i
subcode: permute_inc
$max=-1
$for $i=$n:0
$if $max<$radix[$i]
$max=$radix[$i]
$else
$for $j=$n:0
$if $radix[$j]>$radix[$i]
$call swap, $radix[$i], $radix[$j]
break
$j=$i+1
$k=$n-1
$while $j<$k
$call swap, $radix[$j], $radix[$k]
$j++
$k--
break
$if $i<0
break
もちろん、このコードは論理的にもっと複雑です。読者の練習のために残しておきます。
誰かがjavascriptの順列でどのように行うのか疑問に思っている場合。
Idea/pseudocode
例えば。 'a' + permute(bc)。 bcの置換はbcとcbになります。これら2つを追加すると、abc、acbが得られます。同様に、b + permute(ac)を選択すると、bac、bca ...が処理され、続行されます。
今、コードを見てください
function permutations(arr){
var len = arr.length,
perms = [],
rest,
picked,
restPerms,
next;
//for one or less item there is only one permutation
if (len <= 1)
return [arr];
for (var i=0; i<len; i++)
{
//copy original array to avoid changing it while picking elements
rest = Object.create(arr);
//splice removed element change array original array(copied array)
//[1,2,3,4].splice(2,1) will return [3] and remaining array = [1,2,4]
picked = rest.splice(i, 1);
//get the permutation of the rest of the elements
restPerms = permutations(rest);
// Now concat like a+permute(bc) for each
for (var j=0; j<restPerms.length; j++)
{
next = picked.concat(restPerms[j]);
perms.Push(next);
}
}
return perms;
}
時間をかけてこれを理解してください。このコードは( JavaScriptのpertumation )から取得しました
// C program to print all permutations with duplicates allowed
#include <stdio.h>
#include <string.h>
/* Function to swap values at two pointers */
void swap(char *x, char *y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
/* Function to print permutations of string
This function takes three parameters:
1. String
2. Starting index of the string
3. Ending index of the string. */
void permute(char *a, int l, int r)
{
int i;
if (l == r)
printf("%s\n", a);
else
{
for (i = l; i <= r; i++)
{
swap((a+l), (a+i));
permute(a, l+1, r);
swap((a+l), (a+i)); //backtrack
}
}
}
/* Driver program to test above functions */
int main()
{
char str[] = "ABC";
int n = strlen(str);
permute(str, 0, n-1);
return 0;
}
リファレンス: Geeksforgeeks.org
void permutate(char[] x, int i, int n){
x=x.clone();
if (i==n){
System.out.print(x);
System.out.print(" ");
counter++;}
else
{
for (int j=i; j<=n;j++){
// System.out.print(temp); System.out.print(" "); //Debugger
swap (x,i,j);
// System.out.print(temp); System.out.print(" "+"i="+i+" j="+j+"\n");// Debugger
permutate(x,i+1,n);
// swap (temp,i,j);
}
}
}
void swap (char[] x, int a, int b){
char temp = x[a];
x[a]=x[b];
x[b]=temp;
}
これを作成しました。研究に基づいて、順列すぎます(qwe、0、qwe.length-1);あなたが知っているように、あなたはバックトラックの有無にかかわらずそれを行うことができます
Javaバージョン
/**
* @param uniqueList
* @param permutationSize
* @param permutation
* @param only Only show the permutation of permutationSize,
* else show all permutation of less than or equal to permutationSize.
*/
public static void my_permutationOf(List<Integer> uniqueList, int permutationSize, List<Integer> permutation, boolean only) {
if (permutation == null) {
assert 0 < permutationSize && permutationSize <= uniqueList.size();
permutation = new ArrayList<>(permutationSize);
if (!only) {
System.out.println(Arrays.toString(permutation.toArray()));
}
}
for (int i : uniqueList) {
if (permutation.contains(i)) {
continue;
}
permutation.add(i);
if (!only) {
System.out.println(Arrays.toString(permutation.toArray()));
} else if (permutation.size() == permutationSize) {
System.out.println(Arrays.toString(permutation.toArray()));
}
if (permutation.size() < permutationSize) {
my_permutationOf(uniqueList, permutationSize, permutation, only);
}
permutation.remove(permutation.size() - 1);
}
}
例えば。
public static void main(String[] args) throws Exception {
my_permutationOf(new ArrayList<Integer>() {
{
add(1);
add(2);
add(3);
}
}, 3, null, true);
}
出力:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
Pythonのもう1つ、@ cdigginsのような場所にはありませんが、理解しやすいと思います
def permute(num):
if len(num) == 2:
# get the permutations of the last 2 numbers by swapping them
yield num
num[0], num[1] = num[1], num[0]
yield num
else:
for i in range(0, len(num)):
# fix the first number and get the permutations of the rest of numbers
for perm in permute(num[0:i] + num[i+1:len(num)]):
yield [num[i]] + perm
for p in permute([1, 2, 3, 4]):
print p
クレイジーな人にとって読みやすい#permutation.to_a
のように機能するおもちゃRubyメソッドがあります。ゆっくりですが、5行もあります。
def permute(ary)
return [ary] if ary.size <= 1
ary.collect_concat.with_index do |e, i|
rest = ary.dup.tap {|a| a.delete_at(i) }
permute(rest).collect {|a| a.unshift(e) }
end
end
私はあらゆるサイズの任意の整数の順列を取得するためのコードを書くことを考えていました。つまり、4654を提供し、可能なすべての順列を7654まで取得しました。 「c」で書かれたコードです。単純にコピーして、任意のオープンソースコンパイラで実行できます。しかし、いくつかの欠陥がデバッグされるのを待っています。感謝してください。
コード:
#include <stdio.h>
#include <conio.h>
#include <malloc.h>
//PROTOTYPES
int fact(int); //For finding the factorial
void swap(int*,int*); //Swapping 2 given numbers
void sort(int*,int); //Sorting the list from the specified path
int imax(int*,int,int); //Finding the value of imax
int jsmall(int*,int); //Gives position of element greater than ith but smaller than rest (ahead of imax)
void perm(); //All the important tasks are done in this function
int n; //Global variable for input OR number of digits
void main()
{
int c=0;
printf("Enter the number : ");
scanf("%d",&c);
perm(c);
getch();
}
void perm(int c){
int *p; //Pointer for allocating separate memory to every single entered digit like arrays
int i, d;
int sum=0;
int j, k;
long f;
n = 0;
while(c != 0) //this one is for calculating the number of digits in the entered number
{
sum = (sum * 10) + (c % 10);
n++; //as i told at the start of loop
c = c / 10;
}
f = fact(n); //It gives the factorial value of any number
p = (int*) malloc(n*sizeof(int)); //Dynamically allocation of array of n elements
for(i=0; sum != 0 ; i++)
{
*(p+i) = sum % 10; //Giving values in dynamic array like 1234....n separately
sum = sum / 10;
}
sort(p,-1); //For sorting the dynamic array "p"
for(c=0 ; c<f/2 ; c++) { //Most important loop which prints 2 numbers per loop, so it goes upto 1/2 of fact(n)
for(k=0 ; k<n ; k++)
printf("%d",p[k]); //Loop for printing one of permutations
printf("\n");
i = d = 0;
i = imax(p,i,d); //provides the max i as per algo (i am restricted to this only)
j = i;
j = jsmall(p,j); //provides smallest i val as per algo
swap(&p[i],&p[j]);
for(k=0 ; k<n ; k++)
printf("%d",p[k]);
printf("\n");
i = d = 0;
i = imax(p,i,d);
j = i;
j = jsmall(p,j);
swap(&p[i],&p[j]);
sort(p,i);
}
free(p); //Deallocating memory
}
int fact (int a)
{
long f=1;
while(a!=0)
{
f = f*a;
a--;
}
return f;
}
void swap(int *p1,int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
return;
}
void sort(int*p,int t)
{
int i,temp,j;
for(i=t+1 ; i<n-1 ; i++)
{
for(j=i+1 ; j<n ; j++)
{
if(*(p+i) > *(p+j))
{
temp = *(p+i);
*(p+i) = *(p+j);
*(p+j) = temp;
}
}
}
}
int imax(int *p, int i , int d)
{
while(i<n-1 && d<n-1)
{
if(*(p+d) < *(p+d+1))
{
i = d;
d++;
}
else
d++;
}
return i;
}
int jsmall(int *p, int j)
{
int i,small = 32767,k = j;
for (i=j+1 ; i<n ; i++)
{
if (p[i]<small && p[i]>p[k])
{
small = p[i];
j = i;
}
}
return j;
}
この再帰的なソリューションをANSI Cで記述しました。Permutate関数を実行するたびに、すべてが完了するまで1つの異なる順列が提供されます。グローバル変数は、変数factおよびcountにも使用できます。
#include <stdio.h>
#define SIZE 4
void Rotate(int vec[], int size)
{
int i, j, first;
first = vec[0];
for(j = 0, i = 1; i < size; i++, j++)
{
vec[j] = vec[i];
}
vec[j] = first;
}
int Permutate(int *start, int size, int *count)
{
static int fact;
if(size > 1)
{
if(Permutate(start + 1, size - 1, count))
{
Rotate(start, size);
}
fact *= size;
}
else
{
(*count)++;
fact = 1;
}
return !(*count % fact);
}
void Show(int vec[], int size)
{
int i;
printf("%d", vec[0]);
for(i = 1; i < size; i++)
{
printf(" %d", vec[i]);
}
putchar('\n');
}
int main()
{
int vec[] = { 1, 2, 3, 4, 5, 6 }; /* Only the first SIZE items will be permutated */
int count = 0;
do
{
Show(vec, SIZE);
} while(!Permutate(vec, SIZE, &count));
putchar('\n');
Show(vec, SIZE);
printf("\nCount: %d\n\n", count);
return 0;
}
public class PermutationGenerator
{
private LinkedList<List<int>> _permutationsList;
public void FindPermutations(List<int> list, int permutationLength)
{
_permutationsList = new LinkedList<List<int>>();
foreach(var value in list)
{
CreatePermutations(value, permutationLength);
}
}
private void CreatePermutations(int value, int permutationLength)
{
var node = _permutationsList.First;
var last = _permutationsList.Last;
while (node != null)
{
if (node.Value.Count < permutationLength)
{
GeneratePermutations(node.Value, value, permutationLength);
}
if (node == last)
{
break;
}
node = node.Next;
}
List<int> permutation = new List<int>();
permutation.Add(value);
_permutationsList.AddLast(permutation);
}
private void GeneratePermutations(List<int> permutation, int value, int permutationLength)
{
if (permutation.Count < permutationLength)
{
List<int> copyOfInitialPermutation = new List<int>(permutation);
copyOfInitialPermutation.Add(value);
_permutationsList.AddLast(copyOfInitialPermutation);
List<int> copyOfPermutation = new List<int>();
copyOfPermutation.AddRange(copyOfInitialPermutation);
int lastIndex = copyOfInitialPermutation.Count - 1;
for (int i = lastIndex;i > 0;i--)
{
int temp = copyOfPermutation[i - 1];
copyOfPermutation[i - 1] = copyOfPermutation[i];
copyOfPermutation[i] = temp;
List<int> perm = new List<int>();
perm.AddRange(copyOfPermutation);
_permutationsList.AddLast(perm);
}
}
}
public void PrintPermutations(int permutationLength)
{
int count = _permutationsList.Where(perm => perm.Count() == permutationLength).Count();
Console.WriteLine("The number of permutations is " + count);
}
}
pHPで
$set=array('A','B','C','D');
function permutate($set) {
$b=array();
foreach($set as $key=>$value) {
if(count($set)==1) {
$b[]=$set[$key];
}
else {
$subset=$set;
unset($subset[$key]);
$x=permutate($subset);
foreach($x as $key1=>$value1) {
$b[]=$value.' '.$value1;
}
}
}
return $b;
}
$x=permutate($set);
var_export($x);
リストのすべての可能な順列を出力するPythonのコードは次のとおりです。
def next_perm(arr):
# Find non-increasing suffix
i = len(arr) - 1
while i > 0 and arr[i - 1] >= arr[i]:
i -= 1
if i <= 0:
return False
# Find successor to pivot
j = len(arr) - 1
while arr[j] <= arr[i - 1]:
j -= 1
arr[i - 1], arr[j] = arr[j], arr[i - 1]
# Reverse suffix
arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
print arr
return True
def all_perm(arr):
a = next_perm(arr)
while a:
a = next_perm(arr)
arr = raw_input()
arr.split(' ')
arr = map(int, arr)
arr.sort()
print arr
all_perm(arr)
すべての可能な順列を取得するために辞書式順序アルゴリズムを使用しましたが、再帰アルゴリズムの方が効率的です。再帰アルゴリズムのコードは次の場所にあります: Python recursion permutations
ColdFusionの実装を次に示します(ArrayAppend()へのマージ引数のためにCF10が必要です)。
public array function permutateArray(arr){
if (not isArray(arguments.arr) ) {
return ['The ARR argument passed to the permutateArray function is not of type array.'];
}
var len = arrayLen(arguments.arr);
var perms = [];
var rest = [];
var restPerms = [];
var rpLen = 0;
var next = [];
//for one or less item there is only one permutation
if (len <= 1) {
return arguments.arr;
}
for (var i=1; i <= len; i++) {
// copy the original array so as not to change it and then remove the picked (current) element
rest = arraySlice(arguments.arr, 1);
arrayDeleteAt(rest, i);
// recursively get the permutation of the rest of the elements
restPerms = permutateArray(rest);
rpLen = arrayLen(restPerms);
// Now concat each permutation to the current (picked) array, and append the concatenated array to the end result
for (var j=1; j <= rpLen; j++) {
// for each array returned, we need to make a fresh copy of the picked(current) element array so as to not change the original array
next = arraySlice(arguments.arr, i, 1);
arrayAppend(next, restPerms[j], true);
arrayAppend(perms, next);
}
}
return perms;
}
上記のKhanSharpのjsソリューションに基づいています。
これは、順列のJavaバージョンです
public class Permutation {
static void permute(String str) {
permute(str.toCharArray(), 0, str.length());
}
static void permute(char [] str, int low, int high) {
if (low == high) {
System.out.println(str);
return;
}
for (int i=low; i<high; i++) {
swap(str, i, low);
permute(str, low+1, high);
swap(str, low, i);
}
}
static void swap(char [] array, int i, int j) {
char t = array[i];
array[i] = array[j];
array[j] = t;
}
}
Scalaで
def permutazione(n: List[Int]): List[List[Int]] = permutationeAcc(n, Nil)
def permutationeAcc(n: List[Int], acc: List[Int]): List[List[Int]] = {
var result: List[List[Int]] = Nil
for (i ← n if (!(acc contains (i))))
if (acc.size == n.size-1)
result = (i :: acc) :: result
else
result = result ::: permutationeAcc(n, i :: acc)
result
}
次のJavaソリューションでは、ストリングが不変であるという事実を利用して、反復ごとに結果セットのクローンを作成しないようにします。
入力は「abc」などの文字列になり、出力は可能なすべての順列になります。
abc
acb
bac
bca
cba
cab
public static void permute(String s) {
permute(s, 0);
}
private static void permute(String str, int left){
if(left == str.length()-1) {
System.out.println(str);
} else {
for(int i = left; i < str.length(); i++) {
String s = swap(str, left, i);
permute(s, left+1);
}
}
}
private static String swap(String s, int left, int right) {
if (left == right)
return s;
String result = s.substring(0, left);
result += s.substring(right, right+1);
result += s.substring(left+1, right);
result += s.substring(left, left+1);
result += s.substring(right+1);
return result;
}
同じアプローチを(文字列の代わりに)配列に適用できます:
public static void main(String[] args) {
int[] abc = {1,2,3};
permute(abc, 0);
}
public static void permute(int[] arr, int index) {
if (index == arr.length) {
System.out.println(Arrays.toString(arr));
} else {
for (int i = index; i < arr.length; i++) {
int[] permutation = arr.clone();
permutation[index] = arr[i];
permutation[i] = arr[index];
permute(permutation, index + 1);
}
}
}
アイデアを開拓した の(方言の)言語で実装を投稿せずに、再帰の並べ替え問題を解決することについて、実際に話すことはできません。したがって、完全を期すために、Schemeで実行できる方法の1つを以下に示します。
(define (permof wd)
(cond ((null? wd) '())
((null? (cdr wd)) (list wd))
(else
(let splice ([l '()] [m (car wd)] [r (cdr wd)])
(append
(map (lambda (x) (cons m x)) (permof (append l r)))
(if (null? r)
'()
(splice (cons m l) (car r) (cdr r))))))))
(permof (list "foo" "bar" "baz"))
を呼び出すと、次のようになります。
'(("foo" "bar" "baz")
("foo" "baz" "bar")
("bar" "foo" "baz")
("bar" "baz" "foo")
("baz" "bar" "foo")
("baz" "foo" "bar"))
アルゴリズムの詳細については、他の投稿で十分に説明されているため、説明しません。考え方は同じです。
ただし、再帰的な問題は、Python、C、およびJavaのような破壊的な媒体でモデリングおよび考えるのがはるかに困難になる傾向がありますが、LISPまたはMLでは簡潔に表現できます。
Javaでの私のソリューションです。
public class CombinatorialUtils {
public static void main(String[] args) {
List<String> alphabet = new ArrayList<>();
alphabet.add("1");
alphabet.add("2");
alphabet.add("3");
alphabet.add("4");
for (List<String> strings : permutations(alphabet)) {
System.out.println(strings);
}
System.out.println("-----------");
for (List<String> strings : combinations(alphabet)) {
System.out.println(strings);
}
}
public static List<List<String>> combinations(List<String> alphabet) {
List<List<String>> permutations = permutations(alphabet);
List<List<String>> combinations = new ArrayList<>(permutations);
for (int i = alphabet.size(); i > 0; i--) {
final int n = i;
combinations.addAll(permutations.stream().map(strings -> strings.subList(0, n)).distinct().collect(Collectors.toList()));
}
return combinations;
}
public static <T> List<List<T>> permutations(List<T> alphabet) {
ArrayList<List<T>> permutations = new ArrayList<>();
if (alphabet.size() == 1) {
permutations.add(alphabet);
return permutations;
} else {
List<List<T>> subPerm = permutations(alphabet.subList(1, alphabet.size()));
T addedElem = alphabet.get(0);
for (int i = 0; i < alphabet.size(); i++) {
for (List<T> permutation : subPerm) {
int index = i;
permutations.add(new ArrayList<T>(permutation) {{
add(index, addedElem);
}});
}
}
}
return permutations;
}
}
これは非常に古く、今日のstackoverflowでは話題から外れていることを知っていますが、ブラウザで実行されるという単純な理由で、フレンドリーなjavascriptの回答を提供したかったのです。
また、debugger
ディレクティブブレークポイントを追加したので、コードをステップ実行して(クロムが必要)、このアルゴリズムの動作を確認できます。 chrome(WindowsではF12
またはMacではCMD + OPTION + I
)で開発コンソールを開き、[コードスニペットを実行]をクリックします。これは、@ WhirlWindが彼の回答で提示したものと同じアルゴリズムを実装しています。
ブラウザは、debugger
ディレクティブで実行を一時停止する必要があります。 F8
を使用して、コードの実行を続行します。
function permute(rest, prefix = []) {
if (rest.length === 0) {
return [prefix];
}
return (rest
.map((x, index) => {
const oldRest = rest;
const oldPrefix = prefix;
// the `...` destructures the array into single values flattening it
const newRest = [...rest.slice(0, index), ...rest.slice(index + 1)];
const newPrefix = [...prefix, x];
debugger;
const result = permute(newRest, newPrefix);
return result;
})
// this step flattens the array of arrays returned by calling permute
.reduce((flattened, arr) => [...flattened, ...arr], [])
);
}
console.log(permute([1, 2, 3]));
誰かが私がしなければならなかったような追加のライブラリをロードすることを避ける必要がある場合のために、これがRのアルゴリズムです。
permutations <- function(n){
if(n==1){
return(matrix(1))
} else {
sp <- permutations(n-1)
p <- nrow(sp)
A <- matrix(nrow=n*p,ncol=n)
for(i in 1:n){
A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))
}
return(A)
}
}
使用例:
> matrix(letters[permutations(3)],ncol=3)
[,1] [,2] [,3]
[1,] "a" "b" "c"
[2,] "a" "c" "b"
[3,] "b" "a" "c"
[4,] "b" "c" "a"
[5,] "c" "a" "b"
[6,] "c" "b" "a"
これはJavaの再帰的なコードです。アイデアは、残りの文字を追加するプレフィックスを付けることです。
public static void permutation(String str) {
permutation("", str);
}
private static void permutation(String prefix, String str) {
int n = str.length();
if (n == 0) System.out.println(prefix);
else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str);
}
}
例:
入力= "ABC";出力:
ABC ACB BAC BCA CAB CBA
以下は、std :: next_permutationによって提供される機能と同様に、昇順で次の順列を提供するC++の非再帰的ソリューションです。
void permute_next(vector<int>& v)
{
if (v.size() < 2)
return;
if (v.size() == 2)
{
int tmp = v[0];
v[0] = v[1];
v[1] = tmp;
return;
}
// Step 1: find first ascending-ordered pair from right to left
int i = v.size()-2;
while(i>=0)
{
if (v[i] < v[i+1])
break;
i--;
}
if (i<0) // vector fully sorted in descending order (last permutation)
{
//resort in ascending order and return
sort(v.begin(), v.end());
return;
}
// Step 2: swap v[i] with next higher element of remaining elements
int pos = i+1;
int val = v[pos];
for(int k=i+2; k<v.size(); k++)
if(v[k] < val && v[k] > v[i])
{
pos = k;
val = v[k];
}
v[pos] = v[i];
v[i] = val;
// Step 3: sort remaining elements from i+1 ... end
sort(v.begin()+i+1, v.end());
}
#!/usr/bin/env python
import time
def permutations(sequence):
# print sequence
unit = [1, 2, 1, 2, 1]
if len(sequence) >= 4:
for i in range(4, (len(sequence) + 1)):
unit = ((unit + [i - 1]) * i)[:-1]
# print unit
for j in unit:
temp = sequence[j]
sequence[j] = sequence[0]
sequence[0] = temp
yield sequence
else:
print 'You can use PEN and PAPER'
# s = [1,2,3,4,5,6,7,8,9,10]
s = [x for x in 'PYTHON']
print s
z = permutations(s)
try:
while True:
# time.sleep(0.0001)
print next(z)
except StopIteration:
print 'Done'
['P', 'Y', 'T', 'H', 'O', 'N']
['Y', 'P', 'T', 'H', 'O', 'N']
['T', 'P', 'Y', 'H', 'O', 'N']
['P', 'T', 'Y', 'H', 'O', 'N']
['Y', 'T', 'P', 'H', 'O', 'N']
['T', 'Y', 'P', 'H', 'O', 'N']
['H', 'Y', 'P', 'T', 'O', 'N']
['Y', 'H', 'P', 'T', 'O', 'N']
['P', 'H', 'Y', 'T', 'O', 'N']
['H', 'P', 'Y', 'T', 'O', 'N']
['Y', 'P', 'H', 'T', 'O', 'N']
['P', 'Y', 'H', 'T', 'O', 'N']
['T', 'Y', 'H', 'P', 'O', 'N']
['Y', 'T', 'H', 'P', 'O', 'N']
['H', 'T', 'Y', 'P', 'O', 'N']
['T', 'H', 'Y', 'P', 'O', 'N']
['Y', 'H', 'T', 'P', 'O', 'N']
['H', 'Y', 'T', 'P', 'O', 'N']
['P', 'Y', 'T', 'H', 'O', 'N']
.
.
.
['Y', 'T', 'N', 'H', 'O', 'P']
['N', 'T', 'Y', 'H', 'O', 'P']
['T', 'N', 'Y', 'H', 'O', 'P']
['Y', 'N', 'T', 'H', 'O', 'P']
['N', 'Y', 'T', 'H', 'O', 'P']
これにより、リストを作成せずに一度に1つずつ作成されます。これは、Marios Choudaryの回答と同じ最終結果です(または、Andersがメモに答えているように、C++のnextPermuteを呼び出すだけです)。しかし、これはヒープのアルゴリズム(非再帰バージョン)が再配置され、コンテキストを保存するクラスです。使用されます:
P5=new genPermutes_t(5); // P5.P is now [0,1,2,3,4]
while(!P5.isDone()) {
// use P5.P here
P5.next();
}
コードはC#で承認されていません。変数はヒープの擬似コードからそのままであり、コメントも参照します:
public class genPermutes_t {
public int[] P; // the current permuation
private int n, i; // vars from the original algorithm
private int[] c; // ditto
public genPermutes_t(int count) {
// init algorithm:
n=count;
i=0;
c=new int[n];
for(int j=0;j<n;j++) c[j]=0;
// start current permutation as 0,1 ... n-1:
P=new int[n];
for(int j=0;j<n;j++) P[j]=j;
}
public bool isDone() {
return i>=n; // condition on the original while loop
}
public void next() {
// the part of the loop that spins until done or ready for next permute:
while(i<n && c[i]>=i) {
c[i]=0;
i++;
}
// pulled from inside loop -- the part that makes next permute:
if(i<n) { // if not done
if(i%2==0) swap(0,i);
else swap(c[i], i);
// "print P" removed. User will simply examine it
c[i]+=1;
i=0;
}
}
private void swap(int i1, int i2) {int tmp=P[i1]; P[i1]=P[i2]; P[i2]=tmp;}
}
完成させるために、C++
#include <iostream>
#include <algorithm>
#include <string>
std::string theSeq = "abc";
do
{
std::cout << theSeq << endl;
}
while (std::next_permutation(theSeq.begin(), theSeq.end()));
...
abc
acb
bac
bca
cab
cba
Bourne Shellソリューション-合計4行(パラメーターなしの場合のテストなし):
test $# -eq 1 && echo "$1" && exit
for i in $*; do
$0 `echo "$*" | sed -e "s/$i//"` | sed -e "s/^/$i /"
done
PHPの再帰的なソリューションを次に示します。 WhirlWindの投稿は、ロジックを正確に説明しています。すべての順列の生成は階乗時間で実行されるため、代わりに反復アプローチを使用することをお勧めします。
public function permute($sofar, $input){
for($i=0; $i < strlen($input); $i++){
$diff = strDiff($input,$input[$i]);
$next = $sofar.$input[$i]; //next contains a permutation, save it
$this->permute($next, $diff);
}
}
StrDiff関数はs1
とs2
の2つの文字列を取り、s1
の要素なしでs2
のすべてを含む新しい文字列を返します(重複が問題です)。したがって、strDiff('finish','i')
=> 'fnish'
(2番目の 'i'はnotが削除されます)。