Java 递归地拼写一个单词

Java 递归地拼写一个单词,java,recursion,combinatorics,Java,Recursion,Combinatorics,我得到的是: 编写一个递归程序,给定一个没有空格的字符串,将其分解为字符串的每一个可能的分段,并将其分解为“单词”。也就是说,打印字符串的每个可能版本,并在其中插入空格。给出分段字符串的顺序无关紧要,但必须给出所有可能的分段,不得重复 如果有人能帮忙的话,我完全不知道如何开始 输出应该如下所示: Enter a string: ABCD ABCD A BCD A B CD A B C D A BC D AB CD AB C D ABC D 您得到的输出有一个模式(如中所示,

我得到的是:

编写一个递归程序,给定一个没有空格的字符串,将其分解为字符串的每一个可能的分段,并将其分解为“单词”。也就是说,打印字符串的每个可能版本,并在其中插入空格。给出分段字符串的顺序无关紧要,但必须给出所有可能的分段,不得重复

如果有人能帮忙的话,我完全不知道如何开始

输出应该如下所示:

 Enter a string: ABCD

 ABCD
 A BCD
 A B CD
 A B C D
 A BC D
 AB CD
 AB C D
 ABC D

您得到的输出有一个模式(如中所示,按照这些输出产生的顺序)。考虑输出2-5有什么共同点:

A BCD
A B CD
A B C D
A BC D
因此,看起来您的函数将打印其输入(
ABCD
),然后将第一个字母作为前缀(
a
),并递归查找其剩余字母的所有组合(
BCD
)。这将暗示函数的实际定义采用两个参数——一个已经展开的前缀和一组剩余字母来枚举函数的组合

使用一个字母完成后,我们将另一个字母移到前缀中(
AB
),然后再次递归地查找剩余字母的所有组合(
CD
),以生成下一组输出:

AB CD
AB C D

我会给你一些提示来帮助你:

思考如何递归地解决这个问题。基本上,这可以通过“分而治之”的变化来解决。对于长度为n的给定字符串,有n-1个位置可以插入分隔符空间

因此,如果您有一个长度为2的字符串,则有一个位置可以插入分隔符,还有两个变体:要么插入分隔符,要么不插入分隔符

如果您有一个长度为3的字符串,则在2个位置有2个选择。因此,函数可以创建一个字符串,将空格插入到第一位,并使用未处理的字符串尾部递归调用自己,以生成该子字符串的所有变体。然后创建另一个前缀字符串,其中第一个位置没有插入空格,然后用字符串的其余部分再次调用它自己


对于每个递归调用,它都需要向自己传递已经生成的字符串前缀和剩余未处理的字符串尾部。

感谢您诚实地告诉我这是一个家庭作业。编写递归函数
Foo(n)
的一个技巧是假设
Foo(n-1)
已经正常工作了。在本例中,您的任务是编写一个函数
GenerateSpaceVariationsOfString(string s)
,该函数将string
s
作为参数,并应返回一个包含该字符串所有可能变体的数组。(使递归函数返回其结果比打印其结果更容易——然后,您可以只打印从该函数获得的数组。)假设
s
的长度为n。现在,假设您有一个函数,它可以将
s
减去它的第一个字母,并返回该子字符串所有可能的空间变化的数组-换句话说,假设
GenerateSpaceVariationsOfString(s.substring(1))
将给出
{“BCD”、“BCD”、“BCD”、“BCD”、…}
如果
s
ABCD
。您如何使用它来编写
GenerateSpaceVariationsOfString


(在递归中,您还需要一个基本情况,因此如果
s
的长度为0或1,那么
GenerateSpaceVariationsOfString
应该返回什么?

如果您意识到字符串
s
的分段等于包含
s
本身的集合,则可以实现一个简单的递归算法,以及
s
的每个子串
X
s\X
分段的集合并集。此外,由于您将始终具有
n-1
可能的子字符串,并且您可以在每个点中分段或不分段,因此您将始终以
2^(n-1)
分段结束

通过一个字符串分段的示例更容易理解
ABC

  • {'ABC'}//'ABC'本身
  • {'A','B',C'}//子串'A'联合'BC'={'B',C'}的第一段
  • {'A','BC'}//子字符串'A'并集'BC'的第二段= {'BC'}
  • {'AB',C'}//子字符串'AB'并集第一个也是唯一的'C'分段= {'C'}
  • 1、2、3和4的并集产生字符串的所有分段
    ABC
  • 这几乎直接转化为以下实现:

    public static Set<Set<String>> segment(String s) {
        // `s` itself.
        Set<Set<String>> result = new LinkedHashSet<Set<String>>();
        Set<String> root = new LinkedHashSet<String>();
        root.add(s);
        result.add(root);   
    
        // set union of each substring `X` (prefix) of `s` with `s\X` (rest).
        for (int i = 1; i < s.length(); i++) {   
            String prefix = s.substring(0, i);
            String rest = s.substring(i);
            for (Set<String> segments : segment(rest)) {
                Set<String> segment = new LinkedHashSet<String>();
                segment.add(prefix);
                segment.addAll(segments);
                result.add(segment);
            }
        }
        return result;
    }
    

    把两个字母之间的连接想象成一个位。如果位为1,则在那里插入空格,如果位为0,则不插入空格。因此,如果字符串长度为n,则创建长度为n-1的位序列。然后将位序列视为无符号整数,并循环遍历所有可能的值:000、001、010等


    当然,这不是递归的,所以你不会因此得到赞扬。

    看一看。首先,你知道递归是如何工作的吗?不,我只想知道如何开始的技巧。我知道递归是如何工作的,我不知道如何得到正确的子字符串。@Brendan这不是以否定的方式表示的!我真的觉得在这里得到你的帮助很聪明。我只是很沮丧,为什么我不知道在我需要做编程作业的时候,平台是在寻找递归的algorithm@Brendan:这是递归的<代码>段在
    for
    循环中递归调用:
    for(设置段:段(rest))
    System.out.println(segment("ABC"));
    // [[ABC], [AB, C], [A, B, C], [BC, A]]
    System.out.println(segment("ABCD"));
    // [[D, AB, C], [BCD, A], [D, ABC], [D, A, B, C], [AB, CD], [ABCD], [D, BC, A], [A, B, CD]]