根据Java中的特定字母规则替换生成可能单词的组合

时间:2014-09-02 10:02:51

标签: java recursion

我很难找出以递归方式生成特定字母组合的最佳方法。

目前,我有一个方法可以更改字符串并更改某些字符以创建单个字的替换。

然而,对于单词的不同组合,这不会满足。例如,如果我有“ 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,等等)执行。

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);
            }
        }
    }
}