我想返回一个字符串的所有可能组合,同时保持所有内容的正确顺序并避免重复。原因是什么?我想通过允许假名和汉字的混合来更灵活地回答一些日本测验。因此,我需要所有可能的组合来与用户的答案进行比较。
这是该函数的当前语法:(located here)
Genki.getAlts('{月曜日}と{水曜日}と{金曜日}に{日本語}のクラスがあります', 'げつようび|すいようび|きんようび|にほんご');
花括号中的文本是将由第二个参数中的替代文本替换的文本,我将其简称为替换。但是,替代文本只能替换相同的索引。那就是:
举一个我想要实现的简单示例。说我有以下内容:
Genki.getAlts('...{A}...{B}...', '1|2', true);
我希望它返回所有组合,如下所示。
'...1...{B}...'
'...1...2...'
'...{A}...2...'
'...{A}...{B}...'
当前实现在2-7个给定的替换下效果很好,但是当给定超过8个时,总组合覆盖率开始下降。可以使用以下公式计算组合的总数:Math.pow(2, 8)
,它将返回“ 256”组合进行8次替换,但目前getAlts()仅返回234个连击,这意味着我们缺少22个连击,仅给出我们有91%的组合覆盖率。
这就是我目前遇到的问题。您可以通过下面的链接查看当前代码。 (是的,这是相当荒谬的)自学成才后,我竭尽所能获得尽可能多的连击,但我担心我的数学技能并不那么好。我敢肯定,有一个简单得多的方法可以解决这个问题,而我只是想得太清楚了。
以当前算法失败为例,打开控制台,您应该会看到关于最后一个问题的警告,内容如下:
234/256(91.40625%的连击覆盖8次替换; 22个连击丢失
此问题的代码:
Genki.getAlts('{1:私}はきのう{学校}で{1:写真}を{1:撮}りました。{2:私}は{家}でも{2:写真}を{2:撮}りました。', 'わたし|がっこう|しゃしん|と|わたし|いえ|しゃしん|と', true);
还有一个简单得多的替代品,其中有10个替代品,可以在控制台中执行测试用例:
Genki.getAlts('{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}', '1|2|3|4|5|6|7|8|9|10', true)
是否有任何可能且简单的方式返回一个字符串的所有组合,而不管指定了多少个替换?虽然我确实知道有多少种组合,但是使用Math.pow(2, n)
,我不确定如何正确地将它们全部获得。
我愿意听到有关实现此目的的现有算法或框架。
PS:实际上,该算法可用于2-7次替换,几乎没有问题达到或超过此阈值。但是,当他们这样做时,用户的答案可能会被错误地标记为错误,因此我想避免这种情况。最简单的解决方案显然是避免打破7,但这并非总是可能的,此外,我目前实现这一目标的方法并非最佳,因此我也希望对其进行优化。
答案 0 :(得分:2)
您可以使用二进制数学解决此问题。这是一种生成字符串数组的方法:
function getAlts(str, alt) {
var subs = alt.split('|');
var length = subs.length;
var permutations = Math.pow(2, length);
var results = [];
for (var i = 0; i < permutations; ++i) {
var bitIndex = 0;
var result = str.replace(/\{(.*?)\}/g, function (match, p1) {
var subIndex = bitIndex++;
var bit = length - 1 - subIndex;
return ((1 << bit) & i) ? subs[subIndex] : p1;
});
results.push(result);
}
return results;
}
console.log(getAlts('...{A}...{B}...', '1|2'));
或者,如果您能够使用ES6(ECMAScript 2015),则可以编写generator function以使用更少的内存:
function* getAlts(str, alt) {
var subs = alt.split('|');
var length = subs.length;
var permutations = Math.pow(2, length);
for (var i = 0; i < permutations; ++i) {
var bitIndex = 0;
var result = str.replace(/\{(.*?)\}/g, function (match, p1) {
var subIndex = bitIndex++;
var bit = length - 1 - subIndex;
return ((1 << bit) & i) ? subs[subIndex] : p1;
});
yield result;
}
}
var results = getAlts('{A}{B}{C}{D}{E}{F}{G}{H}{I}', '1|2|3|4|5|6|7|8|9');
var total = 0;
for (var result of results) {
console.log(result);
total++;
}
console.log('total:', total);