我很难找出以递归方式生成特定字母组合的最佳方法。
目前,我有一个方法可以更改字符串并更改某些字符以创建单个字的替换。
然而,对于单词的不同组合,这不会满足。例如,如果我有“ kjng 这个词通常会误认为打印机字符,例如:
[j=>i, i=>j, v=>u, u=>v, s=>f, f=>s, uu=>w, vv=>w] (map lookup, "=>" this is symbolic for key, value representation to make it extra clear)
基于这种方法,这个词将成为王。对于只有一种可能性的单词来说这很好。然而, murdir 会产生以下结果:
murdir
mvrdjr
mvrdir
murdjr
对此的一点建议会很棒,目前我不确定如何最好地管理这种情况。例如,如何跟踪更改,以字符块( 1,然后2,然后3,等等)执行。
答案 0 :(得分:1)
如果您的问题只是跟踪更改,并且您希望确定已生成所有组合,但无 两次,则所有您需要的是找到所有可能组合的排序。
我将可能的替换列表映射到一系列位,如下所示:
j=>i ~ bit 0
i=>j ~ bit 1
v=>u ~ bit 2
u=>v ~ bit 3
s=>f ~ bit 4
f=>s ~ bit 5
uu=>w ~ bit 6
vv=>w ~ bit 7
76543210
00101011 means you replace j=>i, i=>j, u=>v, f=>s
11000001 means you replace j=>i, uu=>w, vv=>w
然后实现某种二进制计数(0,1,10,11,100,101,110,111,1000,1001,1010,1011,1100,...)并根据数字生成组合。
我并不是说它们必须是单个长整型变量的字面值,但是排序的想法就是这个。当然,如果你没有超过64个替换,那么一个长变量是好的:
String input = ...
List<...> replacements = ...
List<String> combinations = new ArrayList<>();
for (long count = 0; count < ...; count++) {
String output = input;
for (bit = 0; bit < 64; bit++) {
if ((count & (1L << bit)) != 0) { // the bit is set
// replace the characters based on replacements.get(bit)
// output = ...
}
}
combinations.add(output);
}
如果您希望让它可以进行更多无限次的替换(> 64),您可以使用相同的想法来排序所有组合的集合并根据Variable Number of Nested For Loops中的想法实现。< / p>
答案 1 :(得分:1)
如果你需要递归地做,那怎么样?这是类似python的伪代码。
#
# make a list of locations of all possible typos
#
s = [] # list
for i in range(0, len(source)):
if source[i] might be typo:
s.append(i)
#
# and to the recursion to find all combinations
#
print do_recurse(source, s)
#
# method that returns the correct char corresponding to the typo
#
def correction(char):
# you should implement
#
# the actual recursion method
#
def do_recurse(str, locations):
'''
return the list of all combinations
'''
if len(locations) <= 0:
return []
ret = []
for loc in locations:
# do the recursion with the string before the modification
r = do_recurse(str, locations[1:])
ret.extend( r )
# do the recursion with the modified string
str[loc] = correction(str[loc])
r = do_recurse(str, locations[1:])
ret.extend( r )
return ret
答案 2 :(得分:1)
一个人用一些规则在某个位置改变一个单词。然后再进一步说明。如果已找到新单词,请停止该案例。
所以基本上你迭代了wordIndex和ruleIndex。递归公式最简单,以后可以改为迭代。你可以进行两级递归:走路规则,走进单词。
好的,在java:
public class Solver {
public static void main(String[] args) {
System.out.println("Solver");
Solver solver = new Solver("j=>i", "i=>j", "v=>u", "u=>v", "s=>f",
"f=>s", "uu=>w", "vv=>w");
//Set<String> words = solver.determineAllWords("murdir");
Set<String> words = solver.determineAllWords("gigi");
words.forEach(System.out::println);
System.out.println("Done");
}
static class Rule {
String from;
String to;
public Rule(String from, String to) {
this.from = from;
this.to = to;
}
}
private final Rule[] rules;
public Solver(String... tofroms) {
this.rules = new Rule[tofroms.length];
for (int i = 0; i < rules.length; ++i) {
String[] tofrom = tofroms[i].split("=>", 2);
rules[i] = new Rule(tofrom[0], tofrom[1]);
}
}
public Set<String> determineAllWords(String word) {
Set<String> solutionWords = new TreeSet<String>(); // Could be a field too.
solutionWords.add(word);
int ruleIndex = 0;
int wordIndex = 0;
solveTryingRules(solutionWords, word, wordIndex, ruleIndex);
return solutionWords;
}
private void solveTryingRules(Set<String> solutionWords,
String word, int wordIndex, int ruleIndex) {
if (ruleIndex >= rules.length) {
return;
}
Rule rule = rules[ruleIndex];
int wordIndexFound = word.indexOf(rule.from, wordIndex);
if (wordIndexFound == -1) {
// Next rule:
solveTryingRules(solutionWords, word, 0, ruleIndex + 1);
} else {
// Keep at same rule,
// Not applying rule to found word position:
solveTryingRules(solutionWords, word, wordIndexFound + 1, ruleIndex);
// Applying rule to found word position:
String nextWord = word.substring(0, wordIndexFound)
+ rule.to
+ word.substring(wordIndexFound + rule.from.length());
boolean added = solutionWords.add(nextWord);
if (added) {
solveTryingRules(solutionWords, nextWord, 0, 0);
}
}
}
}