生成変化なく繰り返/java組み
-
19-09-2019 - |
質問
していますの生成バリエーション全てをせずに繰り返した桁の数字0-9.
長き1-10.ないんですけどこれを解決するために、特にどのような繰り返し.
例:長さの変動4 ランダム変動9856,8753,1243,1234。な9985-を含む繰り返し)
私は本当に感謝して自分がその気にさえなればきっかけにして、自分にはこの問題は、特に一部コードの手がかりになると考えられます。
解決
を探すためのキーワードは、の順列のです。それらを実行自由に利用可能なソースコードの豊富があります。
自由繰り返し、それを維持するためとして、私は単純な再帰的なアプローチを提案:あなたの再帰を2つの再帰呼び出しに数字やフォークを通じてカウントして各桁のためにあなたは、あなたの変化にそれを取るかどうかの選択肢があり、その一つに数字は、それが除外されているものを含まれています。あなたが最後の桁に達した後、次に、それぞれの再帰は、本質的にあなたの繰り返しのない数字の(ユニーク、ソートされた)リストを与えます。あなたは、このリストのすべての可能な順列を作成し、最終的な結果を達成するために、これらの順列の全てを組み合わせることができます。
(duffymoと同じ言った:私はそのためのコードを提供しないであろう)
アドバンスト注:再帰直接ビット、したがって、整数に変換することができる0/1(除外、包含)に基づいています。そのため、実際にあなたは、単にすべての10ビット整数を使用し、それらを反復処理でき再帰自体を行わずにすべての可能な数字の組み合わせを取得するためです。次に、設定されたビットを置換する必要があるリスト内の数字を含むに対応するように番号を解釈します。
他のヒント
ここでは私のJavaコードです。お気軽にお尋ねだんです。のがポイントで:
- 何も文字の配列になります。例えば:a1a2a3b1b2b3....(a1=a2=a3)
- 成換、常に状態:指数a1 < 指a2 < 指a3...
import java.util.Arrays;
public class PermutationDup {
public void permutation(String s) {
char[] original = s.toCharArray();
Arrays.sort(original);
char[] clone = new char[s.length()];
boolean[] mark = new boolean[s.length()];
Arrays.fill(mark, false);
permute(original, clone, mark, 0, s.length());
}
private void permute(char[] original, char[] clone, boolean[] mark, int length, int n) {
if (length == n) {
System.out.println(clone);
return;
}
for (int i = 0; i < n; i++) {
if (mark[i] == true) continue;
// dont use this state. to keep order of duplicate character
if (i > 0 && original[i] == original[i-1] && mark[i-1] == false) continue;
mark[i] = true;
clone[length] = original[i];
permute(original, clone, mark, length+1, n);
mark[i] = false;
}
}
public static void main(String[] args) {
PermutationDup p = new PermutationDup();
p.permutation("abcab");
}
}
私は順序が重要とノー繰り返しである順列を生成するための次のコードを作成しました。これは、任意の型のオブジェクトを並べ替えるためのジェネリックを利用します:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Permutations {
public static <T> Collection<List<T>> generatePermutationsNoRepetition(Set<T> availableNumbers) {
Collection<List<T>> permutations = new HashSet<>();
for (T number : availableNumbers) {
Set<T> numbers = new HashSet<>(availableNumbers);
numbers.remove(number);
if (!numbers.isEmpty()) {
Collection<List<T>> childPermutations = generatePermutationsNoRepetition(numbers);
for (List<T> childPermutation : childPermutations) {
List<T> permutation = new ArrayList<>();
permutation.add(number);
permutation.addAll(childPermutation);
permutations.add(permutation);
}
} else {
List<T> permutation = new ArrayList<>();
permutation.add(number);
permutations.add(permutation);
}
}
return permutations;
}
}
あなたは魔法のような機能を持っていた想像 - 数字の配列を指定して、それはあなたの正しい順列を返します。
どのように1つだけの余分な数字で順列の新しいリストを生成するためにその機能を使用することができますか?
例えば。、
私はあなたにpermute_three(char[3] digits)
という関数を与えた、と私はそれが数字だけ0
のために働くことを教えてくれた場合、、1
、2
、どのように与えられた0
機能を使用して、1
、2
、3
、permute_three
を並べ替えることができます関数を記述することができます?
...
あなたはそれを解決したら、あなたは何に気づくのですか?あなたはそれを一般化することができますか?
ドルを使用すると、それは簡単ですをます:
@Test
public void generatePermutations() {
// digits is the string "0123456789"
String digits = $('0', '9').join();
// then generate 10 permutations
for (int i : $(10)) {
// shuffle, the cut (0, 4) in order to get a 4-char permutation
System.out.println($(digits).shuffle().slice(4));
}
}
のコードを高めることができな重複が加わることで、さらにif-else文です。このチェック コード
上記のコード編集のためのループとしており
for (j = i; j <= n; j++)
{
if(a[i]!=a[j] && !is_duplicate(a,i,j))
{
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j));
}
else if(i!=j) {} // if no duplicate is present , do nothing
else permute(a,i+1,n); // skip the ith character
}
bool is_duplicate(int *a,int i,int j)
{
if a[i] is present between a[j]...a[i]
return 1;
otherwise
return 0;
}
試験
順列が定理に基づいて、結果の量(この場合数の)要素の数の階乗です。あなたのケース10には!である10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 3628800.それは正確に右も発生するための適切なソリューションである理由を証明。 まあそうか。 1つの番号は、左の位置にあり、我々はなど同じ番号を繰り返すことはできませんので、すなわち左から最初の位置にあなたは、第二の位置にあなただけの9の番号を持つことができ、10個の数字を持つことができます(証明は数学的帰納によって行われます)。 それでは、どの最初の10件の結果を生成するには?私の知識をよると、彼は道が巡回シフトを使用する最も単純な。それはナンバーワンの位置を左へのシフト(または右したい場合)、空の場所に配置するオーバーフロー数の順序を意味しています。 これは、最初の10件の結果手段ます:
10 9 8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1 10
8 7 6 5 4 3 2 1 10 9
7 6 5 4 3 2 1 10 9 8
6 5 4 3 2 1 10 9 8 7
5 4 3 2 1 10 9 8 7 6
...
最初の行は、基本的なサンプルがあるので、世代前の設定にそれを置くことをお勧めします。利点は、次のステップであなたは望ましくないduplicitiesを避けるために、同じ問題を解決する必要があること、である。
次のステップでは、再帰的にのみ10-1番号10-1回等を回転させます また、ステップ2で最初の9件の結果を得るための手段
10 9 8 7 6 5 4 3 2 1
10 8 7 6 5 4 3 2 1 9
10 7 6 5 4 3 2 1 9 8
10 6 5 4 3 2 1 9 8 7
10 5 4 3 2 1 9 8 7 6
...
など、それが再設定発生に加えてはならないので、最初の行は、前のステップから存在している旨の通知、。
アルゴリズムは、再帰的に上記で説明されているもの、まさにそれやって。ネストの数は、配列の要素数と同じであるので、(それが5分程度残る10個の数字のために、あなたのケースで意味している。私のコンピュータ上で)!10のためのすべての3628800個の組み合わせを生成することが可能ですし、十分なメモリが必要ですあなたは、アレイ内のすべての組み合わせを保持する場合。
ソリューションがあります。
package permutation;
/** Class for generation amount of combinations (factorial)
* !!! this is generate proper permutations without repeating and proper amount (počet) of rows !!!
*
* @author hariprasad
*/
public class TestForPermutationII {
private static final String BUMPER = "*";
private static int counter = 0;
private static int sumsum = 0;
// definitoin of array for generation
//int[] testsimple = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] testsimple = {1, 2, 3, 4, 5};
private int ELEMNUM = testsimple.length;
int[][] shuff;
private String gaps(int len) {
String addGap = "";
for(int i=0; i <len; i++)
addGap += " ";
return addGap;
}
/** Factorial computing */
private int fact(int num) {
if (num > 1) {
return num * fact(num - 1);
} else {
return 1;
}
}
/** Cyclic shift position to the left */
private int[] lShiftPos(int[] arr, int pos) {
int[] work = new int[ELEMNUM];
int offset = -1;
for (int jj = 0; jj < arr.length; jj++) {
if (jj < pos) {
work[jj] = arr[jj];
} else if (jj <= arr.length - 1) {
if (jj == pos) {
offset = arr[pos]; // last element
}
if (jj != (arr.length - 1)) {
work[jj] = arr[jj + 1];
} else {
work[jj] = offset;
}
}
}
return work;
}
private String printBuff(int[] buffer) {
String res = "";
for (int i= 0; i < buffer.length; i++) {
if (i == 0)
res += buffer[i];
else
res += ", " + buffer[i];
}
return res;
};
/** Recursive generator for arbitrary length of array */
private String permutationGenerator(int pos, int level) {
String ret = BUMPER;
int templen = counter;
int[] work = new int[ELEMNUM];
int locsumread = 0;
int locsumnew = 0;
//System.out.println("\nCalled level: " + level);
for (int i = 0; i <= templen; i++) {
work = shuff[i];
sumsum++;
locsumread++;
for (int ii = 0; ii < pos; ii++) {
counter++;
sumsum++;
locsumnew++;
work = lShiftPos(work, level); // deep copy
shuff[counter] = work;
}
}
System.out.println("locsumread, locsumnew: " + locsumread + ", " + locsumnew);
// if level == ELEMNUM-2, it means no another shift
if (level < ELEMNUM-2) {
ret = permutationGenerator(pos-1, level+1);
ret = "Level " + level + " end.";
//System.out.println(ret);
}
return ret;
}
public static void main(String[] argv) {
TestForPermutationII test = new TestForPermutationII();
counter = 0;
int len = test.testsimple.length;
int[] work = new int[len];
test.shuff = new int[test.fact(len)][];
//initial
test.shuff[counter] = test.testsimple;
work = test.testsimple; // shalow copy
test.shuff = new int[test.fact(len)][];
counter = 0;
test.shuff[counter] = test.testsimple;
test.permutationGenerator(len-1, 0);
for (int i = 0; i <= counter; i++) {
System.out.println(test.printBuff(test.shuff[i]));
}
System.out.println("Counter, cycles: " + counter + ", " + sumsum);
}
}
アルゴリズムの強度(サイクル数)は、メンバーの数の不完全階乗の和です。だから、部分集合が再び次のサブセットを生成するために読み取られるオーバーハングがあるので、強度があります:
N! + N!/ 2! + N!/ 3! + ... + N!/(N-2)! + N!(N-1)!
があり、鉱山からのものではない一つの解決策はあるが、それは非常に素晴らしく、洗練されています。
package permutations;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author Vladimir Hajek
*
*/
public class PermutationSimple {
private static final int MAX_NUMBER = 3;
Set<String> results = new HashSet<>(0);
/**
*
*/
public PermutationSimple() {
// TODO Auto-generated constructor stub
}
/**
* @param availableNumbers
* @return
*/
public static List<String> generatePermutations(Set<Integer> availableNumbers) {
List<String> permutations = new LinkedList<>();
for (Integer number : availableNumbers) {
Set<Integer> numbers = new HashSet<>(availableNumbers);
numbers.remove(number);
if (!numbers.isEmpty()) {
List<String> childPermutations = generatePermutations(numbers);
for (String childPermutation : childPermutations) {
String permutation = number + childPermutation;
permutations.add(permutation);
}
} else {
permutations.add(number.toString());
}
}
return permutations;
}
/**
* @param args
*/
public static void main(String[] args) {
Set<Integer> availableNumbers = new HashSet<>(0);
for (int i = 1; i <= MAX_NUMBER; i++) {
availableNumbers.add(i);
}
List<String> permutations = generatePermutations(availableNumbers);
for (String permutation : permutations) {
System.out.println(permutation);
}
}
}
私は、これは優れたソリューションである、と考えています。
ブリーフ便利順列インデックス知識
{0とNとの間の屈折率値所与正しい順列を生成する方法を作成します! -1}「インデックス付けゼロ」又は{1及びN!}「指標付け1」のため。
下限が1であり、上限がNである「のループ」を含む第二の方法を作成します!例えば.. "(I、iは++ <= N !;)は、" ループのすべてのインスタンスに対しては、引数としてIを渡し、最初のメソッドを呼び出す
。