[递归] 求一个字符串的所有顺序子串

1 题目:

输入参数:一个字符串,这个字符串只包含字母A-Z或者a-z
返回值:返回输入参数的所有顺序子串,不同的子串之间用逗号分隔。
顺序子串的定义是:只由输入参数中出现的字母,按照其在输入参数中出现的顺序组成的字符串。
例如:输入参数为 “abc”,返回值应该为: “abc, ab, ac, bc, a, b, c”。
该函数的Specification为:

/**
 * @param word consisting only of letters A-Z or a-z
 * @return all subsequences of word, separated by commas,
 * where a subsequence is a string of letters found in word 
 * in the same order that they appear in word.
 */
public static String subsequences(String word)

2 递归解法

2.1 分析

假设输入参数为: a1a2a3...an , 其中 a1,a2,...,an 代表输入参数中的每一个字母。
S(n) 表示一个集合, 其元素是: a1 an 共 n 个字母的所有顺序子串, S(n1) 表示一个集合,其元素是: a2 an 共 n-1 个字母的所有顺序子串,以此类推,如下图所示,直到得到 S(1) 的定义。
S(0) 定义为空字符串, 为递归算法的 Base Case, 。

a1a2a3...anS(n1)S(n)

定义函数 concatenate(ai,S(n)) : 表示将 ai 与集合 S(n) 中的每个元素进行连接操作。
于是有如下递归方程:
S(n)=S(n1)concatenate(ai,S(n1))i=lenn+1,len

可以根据下面的例子理解上述方法:
设输入参数为: a1a2a3="abc" "" 代表空字符串
S(0)=""S(1)=S(0)+concatenate(a3,S(0))=c,""
S(1)=c,""S(2)=S(1)+concatenate(a2,S(1))=bc,b,c,""
S(2)=bc,b,c,""S(3)=S(2)+concatenate(a1,S(2)),
S(3)=abc,ab,ac,bc,a,b,c,""
时间复杂度:
由于输入参数所有的子序列都需要输出,将输出参数视为大小为n的集合,子序列为其子集和。大小为n的集合所有子集的个数为 Pow(n)=2n , 所以时间复杂度为 O(2n)

2.2 设计递归方法

2.2.1 根据题目的约定(Specification)设计递归方法
/**
 * @param word consisting only of letters A-Z or a-z
 * @return all subsequences of word, separated by commas,
 * where a subsequence is a string of letters found in word
 * in the same order that they appear in word.
 */
 public static String subsequences(String word) {
      if (word.isEmpty()) {
          return ""; // base case
      } else {
         char firstLetter = word.charAt(0);
         String restOfWord = word.substring(1);

         String subsequencesOfRest = subsequences(restOfWord);

         String result = "";
         for (String subsequence : subsequencesOfRest.split(",", -1)) {
             result += "," + subsequence;
             result += "," + firstLetter + subsequence;
         }
         result = result.substring(1); // remove extra leading comma
         return result;
     }
 }
2.2.2 设计Helper方法使递归更简洁

根据递归方程设计递归方法时候,可以设计helper方法(如下),使递归方程的代码实现更加简洁。
将前i个字母的一个顺序子串作为参数传入递归方法中, 实现同样的功能,使代码量减少,易懂。

/**
 * Return all subsequences of word (as defined above) separated by commas,
 * with partialSubsequence prepended to each one.
 */
private static String subsequencesAfter(String partialSubsequence, String word) {
    if (word.isEmpty()) {
        // base case
        return partialSubsequence;
    } else {
        // recursive step
        return subsequencesAfter(partialSubsequence, word.substring(1))
             + ","
             + subsequencesAfter(partialSubsequence + word.charAt(0), word.substring(1));
    }
}

Reference

[1] 6.005 — Software Construction on MIT OpenCourseWare | OCW 6.005 Homepage at https://ocw.mit.edu/ans7870/6/6.005/s16/

你可能感兴趣的:(算法与数据结构)