找到字符串的组合

时间:2017-06-03 09:24:49

标签: java algorithm

我的字符串格式为'2112'; 可能的组合应代表字母。

2,112是不允许的,因为112是一个三位数字符,它不能代表字母表,所以基本上'a'代表1而'z'代表26。

与此类似,可能的组合是(2,1,1,2),(21,1,2),(2,11,2),(2,1,12),(21,21)。

所以这里的字符没有重新排序,但已被拆分成组合。 我该如何处理?

我的尝试:

public static void main(String[] args) {
    System.out.println(permutationFinder("2112"));
}

private static Set<String> permutationFinder(String str) {
    for (int i = 0; i < str.length(); i++) {

    }



    Set<String> stringSet = new HashSet<>();
    if(str == null){
        return null;
    }
    else if(str.length()==0){
        stringSet.add("");
        return stringSet;
    }
    char initial = str.charAt(0);
    String rem = str.substring(1);
    Set<String> words = permutationFinder(rem);

    for(String word : words){
        int length = word.length();
        for(int i = 0; i <= length; i++){
            stringSet.add(merge(word, initial, i));
        }
    }

    return stringSet;
}

private static String merge(String word, char initial, int i) {
    String begin = word.substring(0,i);
    String end = word.substring(i);
    return begin + initial + end;
}

但是这给了组合。

2 个答案:

答案 0 :(得分:1)

我不明白你的方法应该如何工作,当然也不知道为什么它没有,抱歉。

像这样的组合问题的标准解决方案是递归,一种方法的概念称其为自己完成其任务的一部分。如果您不知道递归,请查阅并准备学习曲线。在这种情况下,我建议该方法在字符串的开头找到可能的第一个字母(在你的例子中它们将是2和21),然后递归调用自己以找到字符串其余部分的所有可能组合,最后放入拼凑在一起形成一个完整的解决方案由于我们总是使用更短的字符串参数调用,因此我们可以确定递归不会无限延续。迟早我们会传递空字符串。所以首先要考虑的是,空字符串的期望结果是什么?这是空的信件清单。现在我们可以编写方法:

private static List<List<String>> combinationFinder(String str) {
    if (str.isEmpty()) {
        return Collections.singletonList(Collections.emptyList());
    }
    List<List<String>> result = new ArrayList<>();
    // can we split off 1 char from the start? requires just non-zero
    if (str.charAt(0) != '0') {
        String firstChar = str.substring(0, 1);
        if (!Character.isDigit(firstChar.charAt(0))) {
            throw new IllegalArgumentException("Not a digit: " + firstChar);
        }
        List<List<String>> combinationsOfRemainingStr 
                = combinationFinder(str.substring(1));
        addAllCombos(result, firstChar, combinationsOfRemainingStr);
    }
    // can we split off 2 chars?
    if (str.length() >= 2) {
        String firstSubstring = str.substring(0, 2);
        int firstNumber = Integer.parseInt(firstSubstring);
        if (firstNumber >= 1 && firstNumber <= 26) { // OK
            List<List<String>> combinationsOfRemainingStr 
                    = combinationFinder(str.substring(2));
            addAllCombos(result, firstSubstring, combinationsOfRemainingStr);
        }
    }
    return result;
}

/** adds to result all lists made up of firstElement followed by a list from remainingElements */
private static void addAllCombos(List<List<String>> result,
        String firstElement, List<List<String>> remainingElements) {
    for (List<String> remCombo : remainingElements) {
        List<String> totalCombo = new ArrayList<>(1 + remCombo.size());
        totalCombo.add(firstElement);
        totalCombo.addAll(remCombo);
        result.add(totalCombo);
    }
}

使用输入示例2112,返回:

[[2, 1, 1, 2], [2, 1, 12], [2, 11, 2], [21, 1, 2], [21, 12]]

我相信这正是你所要求的。

我编写的方法有点不一致:它会从字符串的开头找到01作为字母,但是001和026都没有。如果这是一个问题,我相信你会修复它。

答案 1 :(得分:0)

尝试以下代码

private static Set<String> findCharacterEquivalants(String str){
    Set<String> charEqs = new HashSet<>();
    int strLen = str.length();

    for(int i = 0; i < strLen; i++){
        if(str.charAt(i) == '0'){
            //Skip it since 0 is not a match for any character
            continue;
        }

        //single character which is not zero is always a match
        charEqs.add("" + str.charAt(i));

        switch(str.charAt(i)){
            case '1' : 
                //Check to see whether combination of this char with the next char is a match
                if((i + 1) < strLen){
                    charEqs.add("" + str.charAt(i) + str.charAt(i + 1));
                }
                break;
            case '2' :
                 //Check to see whether combination of this char with the next char is a match.
                if(((i + 1) < strLen)
                          && (str.charAt(i + 1) == '0' || str.charAt(i + 1) == '1' || str.charAt(i + 1) == '2' || str.charAt(i + 1) == '3' || str.charAt(i + 1) == '4' || str.charAt(i + 1) == '5' || str.charAt(i + 1) == '6')){
                    charEqs.add("" + str.charAt(i) + str.charAt(i + 1));
                }
        }
    }

    return charEqs;

}

请注意,此方法假设排列保持提供的字符串中的字符顺序。如果要允许复制这些子字符串,请使用List而不是Set。