递归地拼出一个单词

时间:2011-03-11 15:41:04

标签: 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

5 个答案:

答案 0 :(得分:5)

您已经给出了输出的模式(如,按照产生这些输出的顺序)。考虑输出2-5的共同点:

A BCD
A B CD
A B C D
A BC D

因此,看起来您的函数将打印其输入(ABCD),然后它将第一个字母作为前缀(A),并递归地查找其所有组合剩余的字母(BCD)。这将暗示函数的实际定义有两个参数 - 一个已经扩展的前缀,以及一组枚举组合的剩余字母。

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

AB CD
AB C D

答案 1 :(得分:5)

我会给你提示帮助:

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

因此,如果你有一个长度为2的字符串,你有一个地方可以插入一个分隔符,还有两个变种:你是否插入了分隔符。

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

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

答案 2 :(得分:2)

感谢您对此作业的诚实。编写递归函数Foo(n)的一个技巧是假设Foo(n-1)已经正常工作。在这种情况下,您的任务是编写函数GenerateSpaceVariationsOfString(string s),它将字符串s作为参数,并返回一个包含字符串所有可能变体的数组。 (制作递归函数会更容易返回其结果而不是打印结果的函数 - 然后,您只需打印从函数中获得的数组。)假设s长度为名词的。现在,假设您有一个函数可以使s减去它的第一个字母并返回该子字符串的所有可能空间变体的数组 - 换句话说,假设GenerateSpaceVariationsOfString(s.substring(1))将给{{1}如果{"BCD", "BCD", "BC D", "BC D", ...}s。你怎么能用它来写ABCD

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

答案 3 :(得分:1)

如果您意识到字符串s的分段等于包含s本身的集合,并且每个子字符串X的集合,则可以实现简单的递归算法。 s s\X的细分n-1。此外,由于您总是会有2^(n-1)个可能的子字符串,并且您可以在这些点中分段或不分段,因此您最终会得到ABC段。

通过字符串ABC的分段示例来理解它更简单:

  
      
  1. {'ABC'} //'ABC'本身
  2.   
  3. {'A','B,'C'} //子串'A'联合第一段'BC'= {'B,'C'}
  4.   
  5. {'A','BC'} //子串'A'联合'BC'的第2个分段=   { 'BC'}
  6.   
  7. {'AB','C'} // substring'AB'union 1st,只有'C'=   { 'C'}
  8.   
  9. 1,2,3和4的联合,产生字符串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; } 的所有分段。
  10.   

这几乎直接转化为以下实现:

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]]

示例输出:

{{1}}

答案 4 :(得分:-1)

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

当然,这不是递归的,所以你不会得到它的信任。