如何修复递归字符串检查

时间:2018-03-27 09:41:10

标签: java string recursion

  

在第一个输入行,将有秘密消息(数字序列)。例如 1122

     

在第二个输入行上将有用于以给定格式对消息进行编码的密码:   “{LetterX}{CodeForX}{LetterY}{CodeForY}…”其中原始邮件中的每个LetterX都将使用密码中的CodeForX进行编码。例如的 A1B12C11D2

     

打印可以编码为给定密码的所有可能原始消息的数量。在下一行,打印这些消息。   例如    3 - > AADD ABD CDD

我的想法是检查消息中是否存在字符串开头的任何字母代码(例如“1”,“12”等),如果发现这样,则将其从中删除并递归进行直到结束到达了字符串。

public class Main {
static List<String> gList = new ArrayList<>();

public static void main(String[] args) throws IOException {
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    String message = in.readLine();     // "1122"
    String codeStr = in.readLine();     // "A1B12C11D2"
// SPLITTING LETTERS FROM CODES:
    String [] secretCode = codeStr.split("[^A-Z0-9]+|(?<=[A-Z])(?=[0-9])|(?<=[0-9])(?=[A-Z])");
    int n = secretCode.length / 2;
    String [] letters = new String [n];  // [A  B   C   D]
    String [] codes = new String [n];    // [1  12  11  2]
    for (int i = 0; i < 2 * n; i+=2) {
        letters[i/2] = secretCode[i];
        codes[i/2] = secretCode[i+1];
    }
    CodesCheck(message, letters, codes);
    System.out.println(Arrays.toString(gList.toArray()));
}
static void CodesCheck (String message, String[] letters, String[] codes) {
    for (int i = 0; i < codes.length; i++) {
        if (codes[i].length() <= message.length() && 
            codes[i].equals(message.substring(0, codes[i].length()))) {
            gList.add(letters[i]);
            String newMessage = message.substring(codes[i].length());
            if (newMessage.equals("")) {
                gList.add("|");
                return;
            }
            CodesCheck(newMessage, letters, codes);
        }
    }
}
}

运行上面的代码时,我得到: [A, A, D, D, |, B, D, |, C, D, D, |] - &gt;所以在第二条消息中缺少“A”字母。 当我调试时,我可以看到递归函数以某种方式进行“122”而不是“1122”。

2 个答案:

答案 0 :(得分:1)

那是因为你的递归是这样的:

 * CodesCheck with "1122" and i=0 adds A, then calls itself with "122"
 ** CodesCheck with "122" and i=0 adds A, then calls itself with "22"
 *** CodesCheck with "22" and i=3 adds D, then calls itself with "2"
 **** CodesCheck with "2" and i=3 adds D, then adds | and returns because next message is ""
 *** CodesCheck with "22" returns because i > 3
 ** CodesCheck with "122" continues with i=1, adds B, then calls itself with "2"
 *** CodesCheck with "2" and i=3 adds D, then adds | and returns because next message is ""
 ** CodesCheck with "122" continues with i=2, finds nothing, continues with i=3, finds nothing, returns because i>3
 * CodesCheck with "1122" and i=1 finds nothing, continues with i=2, adds C, calls itself with "22"
 ** CodesCheck with "22" and i=3 adds D, then calls itself with "2"
 *** CodesCheck with "2" and i=3 adds D, then adds | and returns because next message is ""
 ** CodesCheck with "22" returns because i > 3
 * CodesCheck with "1122" continues with i=3, finds nothing, then returns because i > 3

要解决此问题,您需要以某种方式跟踪递归调用,这意味着当"122"上的方法继续i=1B时,您需要知道有之前需要A,您需要在B之前将其添加到列表中。

执行此操作的一种方法是使用stack

void CodesCheck (String message, String[] letters, String[] codes, Stack<String> stack) {

当您调用方法时,只需为其提供空堆栈

CodesCheck(message, letters, codes, new Stack<String>());

然后,不是直接向gList添加字母,而是将它们添加到堆栈,并确保在离开当前递归后,弹出本地字母或迭代分支:

stack.add(letters[i]);
final String newMessage = message.substring(codes[i].length());
if (newMessage.equals("")) {
    gList.addAll(stack);
    gList.add("|");
    stack.pop();
    return;
}
CodesCheck(newMessage, letters, codes, stack);
stack.pop();

答案 1 :(得分:0)

问题不在于功能,而在于输出:

使用A,您有多种可能性,您的程序将打印出来:

A [ output of recursive call with second letter A | ] [ output of recursive call with second letter B |].

你应该做的是让每个调用返回结果gLists(多个),并且调用函数在它们当前字母前面加上。只有到底你应该把|介于两者之间。