如何获得所有可能的子串组合?

时间:2016-02-08 13:52:26

标签: java string algorithm combinations

我有一个以下结构的字符串: A1(N1,N2,N3)P4(O3,O5)Y1

如何获得所有组合?规则是括号内的选项不应该在一起。对于此示例,输出应为:

A1N1P4O3Y1,
A1N2P4O3Y1,
A1N3P4O3Y1,
A1N1P4O5Y1,
A1N2P4O5Y1,
A1N3P4O5Y1.

可以有括号,但也可以没有它。另一个例子:

N3P5(L1,L2)Q1,输出应为:

N3P5L1Q1,
N3P5L2Q1. 

有优雅解决方案的人吗?

1 个答案:

答案 0 :(得分:0)

主要思想是将字符串输入转换为包含部分的StringTemplate,可以是单个字符串或一组字符串。

对于每个部件,都会创建一个迭代器。虽然可以使用一些迭代器,但更新一个包含当前零件值的字符串数组,并重置在更改的零件之前的所有零件迭代器。如果需要,请随意清除重复的代码并添加嵌套组支持和语法验证。

private static StringTemplate parse(String string) {

    List<StringPart> parts = new ArrayList<StringPart>();

    boolean insideGroup = false;
    StringBuilder currentToken = new StringBuilder();

    List<LiteralPart> groupParts = new ArrayList<LiteralPart>();

    for (int i = 0; i < string.length(); i++) {
        char ch = string.charAt(i);

        if (ch == '(') {

            if (currentToken.length() != 0) {
                parts.add(new LiteralPart(currentToken.toString()));
                currentToken.delete(0, currentToken.length());
            }

            insideGroup = true;

        } else if (ch == ')') {

            if (insideGroup) {

                if (currentToken.length() != 0) {
                    groupParts.add(new LiteralPart(currentToken.toString()));
                    currentToken.delete(0, currentToken.length());
                }

                parts.add(new CompositePart(groupParts));
                groupParts.clear();
                insideGroup = false;

            } else {
                currentToken.append(ch);
            }

        } else if (ch == ',') {

            if (insideGroup) {

                if (currentToken.length() != 0) {
                    groupParts.add(new LiteralPart(currentToken.toString()));
                    currentToken.delete(0, currentToken.length());
                }

            } else {
                currentToken.append(ch);
            }

        } else {
            currentToken.append(ch);
        }
    }

    if (currentToken.length() != 0) {
        parts.add(new LiteralPart(currentToken.toString()));
        currentToken.delete(0, currentToken.length());
    }

    return new StringTemplate(parts);

}

private static final class StringTemplate {

    private final List<StringPart> parts;

    public StringTemplate(List<StringPart> parts) {
        this.parts = parts;
    }

    public List<String> getCombinations() {
        List<Iterator<String>> iterators = new ArrayList<Iterator<String>>(parts.size()); 

        for (StringPart part : parts) {
            iterators.add(part.getStrings().iterator());
        }

        String[] toJoin = new String[iterators.size()];

        List<String> combinations = new ArrayList<String>();
        int iteratorThatAdvanced;
        int maxIteratorThatAdvanced = Integer.MIN_VALUE;
        boolean first = true;

        for (;;) {

            iteratorThatAdvanced = -1;

            for (int i = 0; i < iterators.size(); i++) {
                Iterator<String> iterator = iterators.get(i);

                if (first || iterator.hasNext()) {
                    String value = iterator.next();
                    toJoin[i] = value;

                    iteratorThatAdvanced = i;

                    if (!first && i >= maxIteratorThatAdvanced) {
                        maxIteratorThatAdvanced = i;
                        break;
                    }
                }
            }

            if (iteratorThatAdvanced < 0) {
                break;
            }

            if (!first) {
                for (int i = 0; i < iteratorThatAdvanced; i++) {
                    Iterator<String> iterator = parts.get(i).getStrings().iterator();
                    iterators.set(i, iterator);
                    toJoin[i] = iterator.next();
                }
            }

            combinations.add(join(toJoin));
            first = false;

        }

        return combinations;
    }

}

private static String join(String[] strings) {
    StringBuilder builder = new StringBuilder();
    for (String string : strings) {
        builder.append(string);
    }
    return builder.toString();
}

private static abstract class StringPart {

    abstract List<String> getStrings();

}

private static final class LiteralPart extends StringPart {

    private final String literal;

    public LiteralPart(String literal) {
        this.literal = literal;
    }

    @Override
    List<String> getStrings() {
        return Collections.singletonList(literal);
    }

}

private static final class CompositePart extends StringPart {

    private final List<LiteralPart> parts;

    public CompositePart(List<LiteralPart> parts) {
        this.parts = new ArrayList<LiteralPart>(parts);
    }

    @Override
    List<String> getStrings() {
        List<String> strings = new ArrayList<String>(parts.size());

        for (LiteralPart part : parts) {
            strings.add(part.literal);
        }

        return strings;
    }

}

示例:

public static void main(String[] args) {
    StringTemplate template = parse("A1(N1,N2,N3)P4(O3,O5)Y1");

    for (String combination : template.getCombinations()) {
        System.out.println(combination);
    }

    template = parse("N3P5(L1,L2)Q1");

    for (String combination : template.getCombinations()) {
        System.out.println(combination);
    }
}