Java 递归方法生成字符串的所有分区

Java 递归方法生成字符串的所有分区,java,string,algorithm,recursion,Java,String,Algorithm,Recursion,我试图用字符串的分区来解决这个问题。让我们以“abc”为例。 有4个分区-{a,bc},{ab,c},{abc},{a,b,c}。 我正试图编写一个递归方法来生成分区到列表的数组列表,但我很难做到这一点。非常感谢您的帮助 static List<List<String>> partitions = new ArrayList<>(); static List<String> partition = new ArrayList<>();

我试图用
字符串的
分区
来解决这个问题。让我们以“abc”为例。
有4个分区
-
{a,bc},{ab,c},{abc},{a,b,c}。

我正试图编写一个
递归
方法来生成
分区
列表
数组列表
,但我很难做到这一点。非常感谢您的帮助

static List<List<String>> partitions = new ArrayList<>();
static List<String> partition = new ArrayList<>();

static void recurse(int size, String str) {
    if (str.length() <= size) {
        return;
    }
    partition.add(str.substring(0, size));
    for (int i = 1; i < str.length(); i++) {
        if (size < str.length())
            recurse(i, str.substring(size));
    }
    partitions.add(partition);
}
而不是
[[a,b,c],[a,bc],[ab,c],[abc]]

,所以我一定是做错了什么:

recurse(0, "abc");
    System.out.println(partitions.toString());

我认为使用全局变量不是一个好主意

递归函数可以返回分区列表

所以,考虑函数的输入和输出

示例:

static List<List<String>> recursive(String str) {
    List<List<String>> result = new ArrayList<>();

    if (str.length() == 1) {
        result.add(new ArrayList<>());
        result.get(0).add(str);
        return result;
    }

    for (List<String> list : recursive(str.substring(1))) {
        List<String> append = new ArrayList<>(list);
        append.set(0, str.substring(0, 1) + append.get(0));
        List<String> add = new ArrayList<>(list);
        add.add(0, str.substring(0, 1));
        result.add(append);
        result.add(add);
    }
    return result;
}
“ABC”

func(“ABC”)=>func(“BC”)=>func(“C”)

func(“C”)返回[[“C”]]

因此,您可以在“C”前面附加“B”,或者创建一个分区

func(“BC”)返回[[“BC”]、[“B”、“C”]]

然后用“A”

func(“ABC”)返回[[“ABC”]、[“A”、“BC”]、[“AB”、“C”]、[“ABC”]]

代码:

static List<List<String>> recursive(String str) {
    List<List<String>> result = new ArrayList<>();

    if (str.length() == 1) {
        result.add(new ArrayList<>());
        result.get(0).add(str);
        return result;
    }

    for (List<String> list : recursive(str.substring(1))) {
        List<String> append = new ArrayList<>(list);
        append.set(0, str.substring(0, 1) + append.get(0));
        List<String> add = new ArrayList<>(list);
        add.add(0, str.substring(0, 1));
        result.add(append);
        result.add(add);
    }
    return result;
}
静态列表递归(字符串str){
列表结果=新建ArrayList();
如果(str.length()==1){
添加(新的ArrayList());
结果.获取(0).添加(str);
返回结果;
}
对于(列表:递归(str.substring(1))){
List append=新的ArrayList(列表);
append.set(0,str.substring(0,1)+append.get(0));
列表添加=新的ArrayList(列表);
add.add(0,str.substring(0,1));
结果。添加(追加);
结果。添加(添加);
}
返回结果;
}
添加:

此外,您的代码只创建一次
分区
。所以
分区
中的
分区
来自同一个引用

因此,添加或编辑
分区
会影响每个
分区
s

因此,正如您所看到的,所有的
分区都是相同的


由于这些原因,您最好在每个步骤中创建新的
ArrayList
,而不是使用全局变量。

我认为使用全局变量不是一个好主意

递归函数可以返回分区列表

所以,考虑函数的输入和输出

示例:

static List<List<String>> recursive(String str) {
    List<List<String>> result = new ArrayList<>();

    if (str.length() == 1) {
        result.add(new ArrayList<>());
        result.get(0).add(str);
        return result;
    }

    for (List<String> list : recursive(str.substring(1))) {
        List<String> append = new ArrayList<>(list);
        append.set(0, str.substring(0, 1) + append.get(0));
        List<String> add = new ArrayList<>(list);
        add.add(0, str.substring(0, 1));
        result.add(append);
        result.add(add);
    }
    return result;
}
“ABC”

func(“ABC”)=>func(“BC”)=>func(“C”)

func(“C”)返回[[“C”]]

因此,您可以在“C”前面附加“B”,或者创建一个分区

func(“BC”)返回[[“BC”]、[“B”、“C”]]

然后用“A”

func(“ABC”)返回[[“ABC”]、[“A”、“BC”]、[“AB”、“C”]、[“ABC”]]

代码:

static List<List<String>> recursive(String str) {
    List<List<String>> result = new ArrayList<>();

    if (str.length() == 1) {
        result.add(new ArrayList<>());
        result.get(0).add(str);
        return result;
    }

    for (List<String> list : recursive(str.substring(1))) {
        List<String> append = new ArrayList<>(list);
        append.set(0, str.substring(0, 1) + append.get(0));
        List<String> add = new ArrayList<>(list);
        add.add(0, str.substring(0, 1));
        result.add(append);
        result.add(add);
    }
    return result;
}
静态列表递归(字符串str){
列表结果=新建ArrayList();
如果(str.length()==1){
添加(新的ArrayList());
结果.获取(0).添加(str);
返回结果;
}
对于(列表:递归(str.substring(1))){
List append=新的ArrayList(列表);
append.set(0,str.substring(0,1)+append.get(0));
列表添加=新的ArrayList(列表);
add.add(0,str.substring(0,1));
结果。添加(追加);
结果。添加(添加);
}
返回结果;
}
添加:

此外,您的代码只创建一次
分区
。所以
分区
中的
分区
来自同一个引用

因此,添加或编辑
分区
会影响每个
分区
s

因此,正如您所看到的,所有的
分区都是相同的


由于这些原因,您最好在每个步骤中创建新的
ArrayList
,而不是使用全局变量。

如果您更喜欢使用Java 8流而不是传统的迭代,则可以选择:

private Stream<List<String>> partitions(String text) {
    if (text.isEmpty())
        return Stream.of(new ArrayList<>());
    else
        return IntStream.rangeClosed(1, text.length()).boxed()
            .flatMap(i -> partitions(text.substring(i))
                .peek(p -> p.add(0, text.substring(0, i))));
}

如果您不熟悉streams,则可以将
else
子句解释为:对于介于1和字符串长度(包括1)之间的所有数字,将该数字的子字符串的所有分区向前流,然后在每个项的开头插入该数字的子字符串。

,如果您更喜欢使用Java 8流而不是传统的迭代:

private Stream<List<String>> partitions(String text) {
    if (text.isEmpty())
        return Stream.of(new ArrayList<>());
    else
        return IntStream.rangeClosed(1, text.length()).boxed()
            .flatMap(i -> partitions(text.substring(i))
                .peek(p -> p.add(0, text.substring(0, i))));
}

如果您不熟悉streams,
else
子句可以解释为:对于介于1和字符串长度(包括1)之间的所有数字,将该数字的子字符串的所有分区向前流,然后在每个项目的开头插入该数字的子字符串。

您将传入一个大小为3、长度为3的字符串。recurse方法中的第一个检查是返回,如果它们相等。您是正确的,我修复了它,但输出仍然不正确。您正在传入一个大小为3、长度为3的字符串。recurse方法中的第一个检查是返回,如果它们相等。你是正确的,我修复了它,但输出仍然不正确。这也是我的思维过程,但返回对象的递归对我来说非常混乱。代码看起来正确@ikicha的一个小更正是:result.add(newarraylist());它必须是result.add(newarraylist());否则,它将在工作期间投诉compilation@Yohannes是的,你说得对。但是我知道java编译器的最新版本(可能是7+)可以通过类型推断猜测泛型类型,因为我声明
List
@ikicha,你说得对,我想我听说可能是在java 8中。不知什么原因,我的java 7编译器无法从实现中猜出类型。这也是我的思考过程,但返回对象的递归对我来说非常混乱。代码看起来正确@ikicha的一个小更正是:result.add(newarraylist());它必须是result.add(newarraylist());否则,它将在工作期间投诉compilation@Yohannes是的,你说得对。但我知道java编译器的最新版本(可能是7+)可以通过类型推断猜测泛型,因为