Java 如何修复递归字符串检查
在第一条输入线上会有一条秘密信息(数字序列)。e、 g.1122 在第二个输入行中,将使用密码对给定格式的消息进行编码:Java 如何修复递归字符串检查,java,string,recursion,Java,String,Recursion,在第一条输入线上会有一条秘密信息(数字序列)。e、 g.1122 在第二个输入行中,将使用密码对给定格式的消息进行编码: “{LetterX}{CodeForX}{LetterY}{CodeForY}…”其中原始邮件中的每个字母x将使用密码中的CodeForX进行编码。e、 g.A1B12C11D2 打印可编码为给定密码的所有可能原始邮件的编号。在下一行中,打印这些消息。 例如 3->AADD ABD CDD 我的想法是检查消息中是否存在字符串开头的任何字母代码(如“1”、“12”等),如果发现
“{LetterX}{CodeForX}{LetterY}{CodeForY}…”
其中原始邮件中的每个字母x将使用密码中的CodeForX进行编码。e、 g.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);
}
}
}
}
公共类主{
静态列表gList=newarraylist();
公共静态void main(字符串[]args)引发IOException{
BufferedReader in=新的BufferedReader(新的InputStreamReader(System.in));
String message=in.readLine();/“1122”
字符串codeStr=in.readLine();/“A1B12C11D2”
//从代码中拆分字母:
String[]secretCode=codeStr.split(“[^A-Z0-9]+|”(?问题不在于函数,而在于输出:
如果您有多种可能性,您的程序将打印:
A [ output of recursive call with second letter A | ] [ output of recursive call with second letter B |].
相反,您应该做的是让每个调用返回结果glist(multiple),并且调用函数在它们的当前字母前面加上前缀。只有在最后,您才应该将|放在两者之间。这是因为您的递归是这样工作的:
* 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=1
和B
时,您需要知道之前有一个A
,并且需要将其添加到B
之前的列表中
一种方法是使用堆栈
:
void CodesCheck (String message, String[] letters, String[] codes, Stack<String> stack) {
是的,这就是我最初的想法——使用列表列表,但我不确定如何实现它。堆栈在这里工作得很好,如果您在每个步骤中复制列表并在当前字符串之前添加前缀,它也会工作。堆栈的好处是它的性能更好,复制的好处是没有副作用(意味着不需要执行pop)。为了完整起见,使用HashMap(a->12等)和一组字符串固定代码以保留结果。以及适当的回溯:
CodesCheck(message, letters, codes, new Stack<String>());
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();