简体   繁体   English

使用 Java 中的回溯递归打印字符串的所有子序列

[英]Print all sub-sequences of a string using backtracking recursion in Java

I know that's a question that has been asked here a lot, and there is plenty of examples online, but I didn't found one that matches my question.我知道这是一个在这里被问过很多次的问题,网上有很多例子,但我没有找到一个与我的问题相匹配的。


I need to write a code that will receive a string and will print all the different sub-sequences in the order they appear in the word.我需要编写一个代码来接收一个字符串,并按照它们在单词中出现的顺序打印所有不同的子序列。 The solution should have recursive method(s) only, with no loops at all.解决方案应该只有递归方法,根本没有循环。 (should be based on backtracking recursion and arrays or substrings only, apparently) (显然,应该仅基于回溯递归和数组或子字符串)

For example '012' should print: "0", "1", "2", "01", "12", "02", "012"例如“012”应该打印:“0”、“1”、“2”、“01”、“12”、“02”、“012”

at first i was going for something like this:起初我想要这样的东西:

public static void printSubs(String s) {
    printSubsSol(s, "");
}

private static void printSubsSol(String s, String temp) {
    if (s.length()==0) {
        System.out.print(temp+" ");
        return;
    }
    printSubsSol(s.substring(1), temp);
    printSubsSol(s.substring(1),temp+s.charAt(0));
}

Prints: 2 1 12 0 02 01 012打印数:2 1 12 0 02 01 012

I wasn't able to print all the sub-sequences in the right order, so now I tried a different approach using a char array, which with I had a bit more success bum I'm not there yet我无法以正确的顺序打印所有子序列,所以现在我尝试使用 char 数组的不同方法,这让我取得了更大的成功,但我还没有

public class Ex9Q2V4 {
public static void printSubs(String s) {
    char[] tempArr = new char[s.length() - 1];
    printSubsSol(s, 0, 0, tempArr, 1);
    System.out.println('"' + s + '"');
}

private static boolean isSafe(int arrayIndex, int currentIndex, int howMuchToPrint, int length) {
    return (arrayIndex < howMuchToPrint && arrayIndex <= currentIndex && currentIndex < length);
}

private static void printSubsSol(String s, int arrayIndex, int currentIndex, char[] charArr, int howMuchToPrint) {
    if (howMuchToPrint == s.length()) {
        return;
    }
    charArr[arrayIndex] = s.charAt(currentIndex);
    if (arrayIndex == howMuchToPrint - 1) {
        System.out.print("\"");
        printArray(charArr, howMuchToPrint);
        System.out.print("\"" + ", ");
    }
    if (isSafe(arrayIndex + 1, currentIndex + 1, howMuchToPrint, s.length())) {
        printSubsSol(s, arrayIndex + 1, currentIndex + 1, charArr, howMuchToPrint);

    }
    else if (isSafe(arrayIndex, currentIndex + 1, howMuchToPrint, s.length())) {
        printSubsSol(s, arrayIndex, currentIndex + 1, charArr, howMuchToPrint);

    }
    else printSubsSol(s, 0, 0, charArr, howMuchToPrint + 1);
}

// A method that prints the array
private static void printArray(char arr[], int n) {
    if (n != 0) {
        printArray(arr, n - 1);
        System.out.print(arr[n - 1]);
    }
}

} }

Prints: "0", "1", "2", "01", "02", "12", "012"打印:“0”、“1”、“2”、“01”、“02”、“12”、“012”

If possible, I will love to see the solution in both ways.如果可能,我很乐意看到两种方式的解决方案。

Let's see with a loop让我们用一个循环来看看

for (int i = 1; i <= s.length(); i++) {
     for (int j = 0; j + i <= s.length(); j++) {
          System.out.print(s.substring(j, j + i) + " ");
     }
}

You're on the right track with your second idea, you need an index and a length but it seems overcomplicated.您的第二个想法走在正确的轨道上,您需要一个索引和一个长度,但它似乎过于复杂。

static void print(String s, int start, int length) {
    System.out.print(s.substring(start, start + length) + " ");
    if (start + length < s.length())
        print(s, start + 1, length);
    else if (length < s.length())
        print(s, 0, length + 1);
}

First we print the substring.首先我们打印子字符串。

The if condition is the nested loop, if the start index + the length to print is still inferior to the length of the string, we just increment the start index if条件是嵌套循环,如果起始索引+打印长度仍然小于字符串长度,我们只增加起始索引

The else part is the first loop, when you've reached the end of the input string and cannot substring anymore, you set the start index back to 0 and increment the length. else 部分是第一个循环,当您到达输入字符串的末尾并且不能再进行子字符串化时,您将开始索引设置回 0 并增加长度。 If the length is equal to the length of the input, recursion stops如果长度等于输入的长度,递归停止

Of course you should first check if the input is not empty当然你应该首先检查输入是否为空

I found an algorithm in C online and converted it to Java and to use Strings .我在网上找到了一个C的算法并将其转换为Java并使用Strings You can see the article here你可以在这里看到这篇文章

I had to store the values in a TreeSet to get the desired order.我必须将值存储在TreeSet才能获得所需的顺序。

Here is how to call it.这是如何调用它。

        String str = "0123";

        Set<String> set = new TreeSet<>(Comparator
                .comparing(String::length)
                .thenComparing(Comparator.naturalOrder()));

        subseq(str, 0, "", set);

        set.forEach(System.out::println);

And here is the modified algorithm.这是修改后的算法。


    static void subseq(String arr, int index, String subarr,
            Set<String> set) {
        if (index == arr.length()) {
            int l = subarr.length();
            if (l != 0) {
                set.add(subarr.substring(0, l));
            }
        } else {
            subseq(arr, index + 1, subarr, set);
            subarr = subarr
                    + arr.substring(index, index + 1);
            subseq(arr, index + 1, subarr, set);
        }
        return;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM