2 回答

TA贡献1862条经验 获得超7个赞
在不同排列之间有一个相等标准之后,我们需要为每个模式(相等类)建立一个规范形式。然后我们将尝试只生成那些。
在您的情况下,在1s、2s 和3s 的顺序无关紧要的情况下,我们可以决定它们各自的第一次出现必须在 order 中123,并且2不能在没有1和3不没有的情况下出现2。因此,无论模式是aabcbc, aacbcb, bbacac, ..., 还是ccbaba,我们想要生成的唯一形式是112323。或图案时,aaa/ bbb/ccc我们只生成111而不是222或333。
然后我们可以编写一个算法,它遵循这些规范形式的规则:
function patterns(values, len) {
function* recurse(list, used, depth) {
if (depth == len) {
yield list.slice();
} else {
for (let j=0; j<used; j++) { // only put already used values at this position
list[depth] = values[j];
yield* recurse(list, used, depth+1);
}
if (used < values.length) { // or the single next unused value
list[depth] = values[used];
yield* recurse(list, used+1, depth+1); // which is counted as used here
}
}
}
return recurse([], 0, 0);
}
这只是从 distinct 生成特定长度的所有组合values,但您可以在算法中使用相同的方法,从一定数量的非唯一值生成排列。不过它确实变得有点复杂:121如果我们只有122可用的值,则无法实现规范形式,但212仍应生成模式。我们需要调整我们的规则,以便排序要求仅在出现次数相同的元素之间。所以我们必须used为它们保留不同的计数。
function permutationPatterns(elements) {
const len = elements.length;
const unique = new Map(elements.map(el => [el, {value: el, occurrences: 0}]));
let max = 0;
for (const el of elements) {
const o = unique.get(el);
max = Math.max(max, ++o.occurrences);
}
const byOccurrences = Array.from({length: max+1}, () => ({elements: [], used: 0}));
for (const o of unique.values()) {
byOccurrences[o.occurrences].elements.push(o);
}
function* generate(list, depth) {
if (depth == len) {
yield list.slice();
} else {
for (const options of byOccurrences) {
options.used++;
for (const option of options.elements.slice(0, options.used)) {
if (option.occurrences == 0) continue;
option.occurrences--;
list[depth] = option.value;
yield* generate(list, depth+1);
option.occurrences++;
}
options.used--;
}
}
}
return generate([], 0);
}

TA贡献1921条经验 获得超9个赞
如果12和21相同,就像10和01毕竟相同,那么首先不要创建所有这些。这里的关键思想是为每个值都有一个规范的形式,例如可以是数字按升序排序。所以你只有值00, 01, 02, 11,12和22。
如果序列中的顺序也不重要,那么您不应该生成排列。同样,为序列选择规范形式。
然后,您可以轻松地仅生成升序形式,并为您的部分和整个序列使用相同的生成器一次:
function* generate(values, len) {
if (len == 0)
yield [];
else
for (const [i, val] of values.entries())
for (const rest of generate(values.slice(i), len-1))
yield [val, ...rest];
}
const duos = Array.from(generate([0, 1, 2], 2), x => x.join(""));
for (const x of generate(duos, 3))
console.log(x.join(" "))
添加回答
举报