当前位置: 首页 > 知识库问答 >
问题:

递归打印仅字典上较大的子字符串

汪阿苏
2023-03-14

我正在编写一段代码,用于递归地只打印字符串的字典序较大的子字符串。

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。后来对该列表进行排序,比较字符串,瞧,就这样完成了。

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

共有1个答案

申高峰
2023-03-14

我会这样做,没有递归,没有额外的字符串构建和忽略,没有输入中重复字母引起的重复。

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

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, 0, 3, 3, 0, 3, 3, 0, 2, 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, 3, 3, 0, 3, 3, 0, 2, 2, 0] (starting buffer, not returned)
    //                    -> [1, 0, 3, 3, 0, 3, 3, 2, 0, 0, 2]
    //                    -> [1, 0, 3, 3, 0, 3, 3, 2, 0, 2, 0]
    //                    -> [1, 0, 3, 3, 0, 3, 3, 2, 2, 0, 0]
    //                    -> [1, 0, 3, 3, 2, 0, 0, 0, 2, 3, 3]
    //                    -> [1, 0, 3, 3, 2, 0, 0, 0, 3, 2, 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);

“球”的输出

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
 类似资料:
  • 我想按以下顺序打印子字符串:-“”,“D”,“C”,“CD”,“B”,“BD”,“BC”,“BCD”,“A”,“AD”,“AC”,“ACD”,“AB”,“ABD”,“ABC”,“ABCD” 在这里,最后4个阵型的“a”不见了

  • 我试图编写一个方法,使用递归打印字符串的所有排列。现在,我有这样的代码: 它打印出正确的结果,但我试图在不使用循环的情况下解决它,包括第4行中的循环。可能吗?如果是这样,你会如何解决?非常感谢。 我试图添加第三个名为index的参数,并在第5行的递归调用中写入index 1,但没有成功。我认为添加第三个参数是个好主意,我只是不知道如何使用它。

  • 问题内容: G’day, 我试图找到拖网字典的函数的递归深度,但我有点迷路了……目前,我有类似以下内容: 我想知道嵌套最多的字典是如何嵌套的…所以我要做以下… 唯一的问题是,递归循环仅返回最终值(0)的返回值。如果我输入一条打印语句, 那么我至少可以打印出最高的递归值,但是返回值是另一回事… 我敢肯定,这很简单-我刚买了果冻脑。 干杯 问题答案: 确保将递归调用的结果分配给 depth 。此外,正

  • 我编写了这个java-fx程序,它在没有递归实现的情况下工作得很好。我编写了操作lambda上的按钮,以确保程序在转换为递归之前正常工作。在过去的几个小时里,我一直在尝试找出两个必需的递归,以及如何使用按钮调用它们。onAction lambda表达式,但需要向正确的方向推动。这是我的。 我想做的是让按钮操作调用递归方法,但我对如何用对递归的调用替换当前操作感到困惑。 在熟睡之后,下面是我对这两个

  • 问题内容: 我想打印一个特定的Python字典键: 现在我可以检查是否可以,但是我想做的是打印密钥的名称。当然可以使用,但是我不想列出 所有 键,而只列出一个特定的键。例如,我期望这样的事情(用伪代码): 有什么方法可以打印键名? 编辑: 好的,非常感谢你们的反应!:)我意识到我的问题没有很好地表述和琐碎。我只是感到困惑,因为我意识到key_name是两个不同的东西,我认为从字典上下文中打印出来是

  • 12.3. Display,一个递归的值打印器 接下来,让我们看看如何改善聚合数据类型的显示。我们并不想完全克隆一个fmt.Sprint函数,我们只是构建一个用于调试用的Display函数:给定任意一个复杂类型 x,打印这个值对应的完整结构,同时标记每个元素的发现路径。让我们从一个例子开始。 e, _ := eval.Parse("sqrt(A / pi)") Display("e", e) 在