厳密に言えば、これらは順列ではなく、有限領域上のシーケンスです。
自明なアルゴリズムは、すべてのシーケンスを生成し、制限を満たすシーケンスのみを出力することです。ドメイン A で長さ n のすべてのシーケンスを生成することは、再帰を使用すると非常に簡単です。
class SequenceGenerator {
char[] domain;
char[] sequence;
int n;
void generate(int i) {
if (i == n) {
System.out.println(new String(sequence));
} else {
for (char c : domain) {
sequence[i] = c;
generate(i + 1);
}
}
}
}
より洗練されたアルゴリズムは、部分的に形成されたシーケンスをチェックします。たとえば、シーケンスが AB で始まることがわかっている場合、それが制限シーケンス [0] == シーケンス [1] を満たさないことはすでにわかっているため、残りの要素を埋める意味はありません。
abstract class PickySequenceGenerator extends SequenceGenerator {
@Override
void generate(int i) {
if (possible(i)) {
super.generate(i);
}
}
/** @return whether a sequence starting with the first i elements of {@link #sequence} can still satisfy all constraints */
abstract boolean possible(int i);
}
効率をさらに高めるために、最も制約のあるシーケンス要素に最初に値を割り当てることができます。