仅递归打印按字典顺序更大的子字符串

问题描述

我正在编写代码,以递归方式仅打印按字典顺序排列的较大子字符串。

static ArrayList<String> getPermutations(String str) {
    if (str.length() == 0) {
        ArrayList<String> tempArrayList = new ArrayList<String>();
        tempArrayList.add("");
        return tempArrayList;
    }

    char currChar = str.charat(0);
    ArrayList<String> resultArrayList = new ArrayList<String>();
    ArrayList<String> recResult = getPermutations(str.substring(1));

    for (String j : recResult) {
        for (int i = 0; i < str.length(); i++) {
            resultArrayList.add(j.substring(0,i) + currChar + j.substring(i));
        }
    }
    return resultArrayList;
}

public static void main(String args[]) {
    Scanner sc = new Scanner(system.in);
    String str = sc.nextLine();
    ArrayList<String> al = getPermutations(str);
    Collections.sort(al);
    // System.out.println(al.toString());
    int index = al.lastIndexOf(str);
    while (index < al.size() - 1) {
        System.out.println(al.get(index + 1));
        index++;
    }
}

代码运行正常。我在这里所做的是递归地生成所有子字符串,并将它们同时插入到ArrayList中。后来对列表进行排序,比较了字符串和样式。

现在让我困扰的是该程序的复杂性。在这里,我生成所有子字符串,然后从中选择。对于递归,我觉得这是一个自动化的过程,所有子字符串都必须至少创建或访问一次。 因此,在这一点上,我想问一下是否可以像在递归函数中进行某种检查那样对其进行优化,以便仅创建所需的子字符串(按字典顺序更大)。如果是,那么请详细说明在基于递归的解决方案中如何考虑它。

解决方法

我会这样,不会递归,不会构建和忽略多余的字符串,不会因输入中的重复字母引起重复。

希望代码中的注释足以理解逻辑。

static List<String> getLargerPermutations(String input) {
    // Build ordered array of unique characters in the input string
    // E.g. "mississippi" -> ['i','m','p','s']
    char[] buf = input.toCharArray();
    Set<Character> charSet = new TreeSet<>();
    for (char ch : buf)
        charSet.add(ch);
    Character[] chars = charSet.toArray(Character[]::new);
    
    // Build map of character to index into CharCount array
    // E.g. "mississippi" -> { i=0,m=1,p=2,s=3 }
    Map<Character,Integer> charIndex = new HashMap<>();
    for (int i = 0; i < chars.length; i++)
        charIndex.put(chars[i],i);
    
    // Build position indexes with starting index for input string
    // E.g. "mississippi" -> [1,3,2,0]
    int[] idx = new int[buf.length];
    for (int i = 0; i < buf.length; i++)
        idx[i] = charIndex.get(buf[i]);
    
    // Build permutations by "incrementing" the indexes
    // E.g. "mississippi" -> [1,0] (starting buffer,not returned)
    //                    -> [1,2]
    //                    -> [1,0]
    //                    -> [1,3]
    //                    -> [1,3]
    List<String> permutations = new ArrayList<>();
    int[] counts = new int[chars.length];
    OUTER: for (int i = idx.length - 1; i >= 0; i--) { // keep going backwards to advance character at previous position:
        counts[idx[i]]++;                              //   return character at current position to pool
        while (++idx[i] < chars.length) {              //   try next character at current position:
            if (counts[idx[i]] > 0) {                  //     if character is available:
                counts[idx[i]]--;                      //       take character from pool
                buf[i] = chars[idx[i]];                //       place character in buffer
                i++;                                   //       advance to next position
                if (i == buf.length) {                 //       if buffer full:
                    permutations.add(new String(buf)); //         we have a good permutation
                    continue OUTER;                    //         continue outer loop to advance to next permutation
                }
                idx[i] = -1;                           //       clear search index of next position
            }
        }                                              //   loop back to try next character
    }                                                  // out of characters at current position,so loop back to try previous position
    return permutations;
}

测试

getLargerPermutations("ball").forEach(System.out::println);

输出为"ball"

blal
blla
labl
lalb
lbal
lbla
llab
llba

输出为"powwow"

powwwo
pwooww
pwowow
pwowwo
pwwoow
pwwowo
pwwwoo
woopww
woowpw
woowwp
wopoww
wopwow
wopwwo
wowopw
wowowp
wowpow
wowpwo
wowwop
wowwpo
wpooww
wpowow
wpowwo
wpwoow
wpwowo
wpwwoo
wwoopw
wwoowp
wwopow
wwopwo
wwowop
wwowpo
wwpoow
wwpowo
wwpwoo
wwwoop
wwwopo
wwwpoo