【问题标题】:Recursive method to generate all partitions of a String生成字符串的所有分区的递归方法
【发布时间】:2017-08-01 12:07:44
【问题描述】:

我正在尝试使用partitioningString 来解决这个问题。我们以“abc”为例。
有 4 个partitions - {a,bc}, {ab,c}, {abc}, {a,b,c}.
我正在尝试编写一个recursive 方法来生成partitionsArrayListLists,但我很难这样做。非常感谢您的帮助!

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, ab], [, a, b, ab], [, a, b, ab], [, a, b, ab]]

而不是[[a, b, c], [a, bc], [ab, c], [abc]]

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

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

【问题讨论】:

  • 你传入一个大小为 3 的字符串和一个长度为 3 的字符串。递归方法中的第一次检查说如果它们相等则返回
  • 你说得对,我修好了,但输出还是不对。

标签: java string algorithm recursion


【解决方案1】:

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

递归函数可能会返回分区列表。

所以,想想函数的输入和输出

示例:

“ABC”

func("ABC") =&gt; func("BC") =&gt; func("C")

func("C") returns [["C"]]

因此您可以在 "C" 前面附加 "B" 或创建一个分区。

func("BC") returns [["BC"], ["B", "C"]]

然后用 "A"

再次执行上述操作

func("ABC") returns [["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;
}

添加:

此外,您的代码只创建一次partition。所以partitions 中的partitions 来自同一个参考!

因此,添加或编辑partition 会影响每个partitions。

所以,如您所见,所有partitions 都是相同的。

由于这些原因,你最好每一步都创建一个新的ArrayList,而不是使用全局变量。

【讨论】:

  • 这也是我的思考过程,但是返回对象的递归让我很困惑
  • 代码看起来是正确的。 @ikicha,对:result.add(new ArrayList()); 的一个小修正它必须是 result.add(new ArrayList());否则编译时会报错
  • @Yohannes 是的,你是对的。但我知道最近版本的 java 编译器(可能是 7+)可以通过类型推断来猜测泛型类型,因为我声明了 List&lt;List&lt;String&gt;&gt;
  • @ikicha,你说得对,我想我听说过,可能是在 java 8 中。由于未知原因,我的 java 7 编译器无法从实现中猜出类型。
【解决方案2】:

如果您更喜欢使用 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))));
}

例如,partitions("abcde").forEach(System.out::println) 将打印字符串的所有分区。

如果你想转换回列表,那么:

List<List<String>> partitions = partitions(text).collect(Collectors.toList());

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 1970-01-01
    • 2021-07-08
    • 1970-01-01
    • 2010-10-28
    • 2018-07-07
    • 2013-12-23
    相关资源
    最近更新 更多