Java 查找与给定字符串相加的所有子字符串的组合

Java 查找与给定字符串相加的所有子字符串的组合,java,string,algorithm,recursion,iteration,Java,String,Algorithm,Recursion,Iteration,我试图创建一个数据结构,其中包含所有可能的子字符串组合,这些子字符串组合加起来就是原始字符串。例如,如果字符串是“java”,有效结果将是“j”、“ava”、“ja”、“v”、“a”,无效结果将是“ja”、“a”或“a”、“jav” 我很容易找到所有可能的子字符串 String string = "java"; List<String> substrings = new ArrayList<>(); for( int c = 0 ; c <

我试图创建一个数据结构,其中包含所有可能的子字符串组合,这些子字符串组合加起来就是原始字符串。例如,如果字符串是
“java”
,有效结果将是
“j”、“ava”
“ja”、“v”、“a”
,无效结果将是
“ja”、“a”
“a”、“jav”

我很容易找到所有可能的子字符串

    String string = "java";
    List<String> substrings = new ArrayList<>();
    for( int c = 0 ; c < string.length() ; c++ )
    {
        for( int i = 1 ; i <= string.length() - c ; i++ )
        {
            String sub = string.substring(c, c+i);
            substrings.add(sub);
        }
    }
    System.out.println(substrings);
String=“java”;
List substring=new ArrayList();
对于(int c=0;c< string·Limthh);C++
{
对于(inti=1;i,这里有一种方法:

static List<List<String>> substrings(String input) {

    // Base case: There's only one way to split up a single character
    // string, and that is ["x"] where x is the character.
    if (input.length() == 1)
        return Collections.singletonList(Collections.singletonList(input));

    // To hold the result
    List<List<String>> result = new ArrayList<>();

    // Recurse (since you tagged the question with recursion ;)
    for (List<String> subresult : substrings(input.substring(1))) {

        // Case: Don't split
        List<String> l2 = new ArrayList<>(subresult);
        l2.set(0, input.charAt(0) + l2.get(0));
        result.add(l2);

        // Case: Split
        List<String> l = new ArrayList<>(subresult);
        l.add(0, input.substring(0, 1));
        result.add(l);
    }

    return result;
}

这似乎是找到字符串长度的最大值,并使用这些组合来生成子字符串的问题。因此有2^n-1个数字n的组合,这可能会使长字符串有点耗时…

可能有人想要另一种非递归且不需要内存来保存列表的解决方案:

public static List<List<String>> substrings(final String input) {
    if(input.isEmpty())
        return Collections.emptyList();
    final int size = 1 << (input.length()-1); 
    return new AbstractList<List<String>>() {

        @Override
        public List<String> get(int index) {
            List<String> entry = new ArrayList<>();
            int last = 0;
            while(true) {
                int next = Integer.numberOfTrailingZeros(index >> last)+last+1;
                if(next == last+33)
                    break;
                entry.add(input.substring(last, next));
                last = next;
            }
            entry.add(input.substring(last));
            return entry;
        }

        @Override
        public int size() {
            return size;
        } 
    };
}

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

它只是根据索引计算下一个组合。

为了防止有人在python中寻找相同的算法,这里是python中的实现:

来自itertools导入组合的

def成分:
n=长(s)
对于范围(n)内的k:
对于组合中的c(范围(1,n),k):
在zip((0,)+c,c+(n,))中i,j的产出元组(s[i:j]
其工作原理示例:

构图中x的('abcd'): …打印(x) (‘abcd’,) (“a”、“bcd”) (‘ab’、‘cd’) (‘abc’、‘d’) (‘a’、‘b’、‘cd’) (‘a’、‘bc’、‘d’) (‘ab’、‘c’、‘d’) (‘a’、‘b’、‘c’、‘d’)
只需稍作修改,您就可以按不同顺序生成合成:

def compositions(s):
    n = len(s)
    for k in range(n):
        for c in itertools.combinations(range(n - 1, 0, -1), k):
            yield tuple(s[i:j] for i, j in zip((0,) + c[::-1], c[::-1] + (n,)))
它将为您提供以下信息:

构图中x的('abcd'): …打印(x) (‘abcd’,) (‘abc’、‘d’) (‘ab’、‘cd’) (“a”、“bcd”) (‘ab’、‘c’、‘d’) (‘a’、‘bc’、‘d’) (‘a’、‘b’、‘cd’) (‘a’、‘b’、‘c’、‘d’) 通过另一个小的添加,您只能生成指定数量的拆分:

def成分(s,r=无):
n=长(s)
r=范围(n),如果r不是其他值[r-1]
对于r中的k:
对于itertools.组合中的c(范围(n-1,0,-1),k):
在zip((0,)+c[::-1],c[::-1]+(n,))中为i,j生成元组(s[i:j]
对于构图中的x('abcd',3): …打印(x) (‘ab’、‘c’、‘d’) (‘a’、‘bc’、‘d’) (‘a’、‘b’、‘cd’)
一个不同的递归解决方案,它只是将结果添加到列表中

static List<List<String>> substrings(String input) {
    List<List<String>> result = new ArrayList<>();
    if (input.length() == 1) {
        result.add(Arrays.asList(new String[]{input}));
    }
    else {
        //iterate j, ja, jav, jav
        for (int i = 0; i < input.length()-1; i++ ) {
            String root = input.substring(0,i+1);
            String leaf = input.substring(i+1);
            for( List<String> strings: substrings(leaf) ) {
                ArrayList<String> current = new ArrayList<String>();
                current.add(root);
                current.addAll(strings);
                result.add(current);
            }
        }
        //adds the whole string as one of the leaves (ie. java, ava, va, a)
        result.add(Arrays.asList(new String[]{input}));
    }
    return result;
}
静态列表子字符串(字符串输入){
列表结果=新建ArrayList();
if(input.length()==1){
add(Arrays.asList(新字符串[]{input}));
}
否则{
//迭代j,ja,jav,jav
对于(int i=0;i
列表来保存有效的子字符串有什么问题?或者你真的想找到一个数据类型来有效地只表示有效的子字符串吗?假设你指的是正确的子字符串,因为空字符串也是一个子字符串。不,不,这与结构无关,我正在构造一个
集,但它甚至可能是两个维数组,我的问题是逻辑,如何找到合适的substrings@aioobe是的,正确的非空子字符串你应该尝试递归:取第一个字符,然后拆分或不拆分,并对其余字符进行分区。我印象深刻,因为我需要更多字符来发表评论,我只想重复一次,我对发表评论感激不尽。很好查看问题练习。我发现这些类型的问题很难快速正确回答。对我来说,这确实很难,另外一个诀窍是,在你真正尝试之前,它看起来很容易,再次感谢。你真是太棒了!!!我能得到这个问题的javascript版本吗?当我尝试用javascript做这件事时,我的浏览器挂起。@kashyaphp注意长度为n的字符串有2^(n-1)结果,所以不要在输入太大的情况下尝试。我喜欢这个解决方案!!使用列表数组而不是列表数组是有意义的。数组索引将与字符串划分为子字符串的方式相对应。例如,元素6将对应于二进制110,它在第一个空格中不放逗号,在第二个空格中放逗号,等等第三位是逗号:[ja,v,a]。@EdwardDoolittle,对于列表数组,有必要将所有的组合存储到内存中,因为Java中不能有一个动态计算的数组。除了列表索引,我也做了同样的操作。
def compositions(s):
    n = len(s)
    for k in range(n):
        for c in itertools.combinations(range(n - 1, 0, -1), k):
            yield tuple(s[i:j] for i, j in zip((0,) + c[::-1], c[::-1] + (n,)))
static List<List<String>> substrings(String input) {
    List<List<String>> result = new ArrayList<>();
    if (input.length() == 1) {
        result.add(Arrays.asList(new String[]{input}));
    }
    else {
        //iterate j, ja, jav, jav
        for (int i = 0; i < input.length()-1; i++ ) {
            String root = input.substring(0,i+1);
            String leaf = input.substring(i+1);
            for( List<String> strings: substrings(leaf) ) {
                ArrayList<String> current = new ArrayList<String>();
                current.add(root);
                current.addAll(strings);
                result.add(current);
            }
        }
        //adds the whole string as one of the leaves (ie. java, ava, va, a)
        result.add(Arrays.asList(new String[]{input}));
    }
    return result;
}