java – 递归字符串解压缩

我正在尝试解压缩看起来如下的字符串:

输入:4(ab)

产出:abababab

输入:11ab

输出:aaaaaaaaaaab

输入:2(3b3(ab))

产出:bbbabababbbbababab

以上示例都使用下面的递归方法正确显示,但是当我输入类似的内容时出现问题:

输入:4(ab)a

预期产量:ababababa

输入:2(3b3(ab))a

预期产量:bbbabababbbbabababa

我意识到问题出现在返回语句“返回重复”中.在当前状态下,递归继续,直到它到达输入字符串的末尾,即使在结束括号之后.基本上我不知道如果到达最后的括号如何让它破坏,然后如果还剩下什么就继续.在2(3b3(ab))a中它应该返回2 *(3b3(ab))a,现在它返回2 *(3b3(ab))a.非常感谢任何帮助,因为我无法理解它.

public static String decompress(String compressedText) throws Exception
{
   //BASE CASE 
    if(compressedText.length() == 1)
    {
        if(compressedText.charAt(0) == ')')
        {
            System.out.println("1: " + compressedText);
            return "";
        }
        else
        {
            System.out.println("2: " + compressedText);
            return compressedText;
        }

    }
    //END BASECASE


    if(compressedText.charAt(0) == '(')
    {
        System.out.println("3: " + compressedText);
        return decompress(compressedText.substring(1));        
    }


    //IF DOUBLE DIGIT
    if(Character.isDigit(compressedText.charAt(0)) == true && Character.isDigit(compressedText.charAt(1)) == true)
    {
        if(compressedText.charAt(3) != '(')
        {
            System.out.println("4: " + compressedText);
            int i = Integer.parseInt(compressedText.substring(0,2));
            String repeated = new String(new char[i]).replace("\0", compressedText.substring(2,3));  
            return repeated + decompress(compressedText.substring(3));
        }
        else
        {
            System.out.println("5: " + compressedText);
            int i = Integer.parseInt(compressedText.substring(0,2));
            String repeated = new String(new char[i]).replace("\0", decompress(compressedText.substring(2)));
            return repeated;
        }

    }
    //END DOUBLE DIGIT



    //IF SINGLE DIGIT
    if (Character.isDigit(compressedText.charAt(0)) == true)
    {
        if(compressedText.charAt(1) !='(')
        {
            System.out.println("6: " + compressedText);
            int i = Integer.parseInt(compressedText.substring(0,1));
            String repeated = new String(new char[i]).replace("\0", compressedText.substring(1,2));  
            return repeated + decompress(compressedText.substring(2)); 
        }
        else
        {
            System.out.println("7: " + compressedText);
            int i = Integer.parseInt(compressedText.substring(0,1));
            String repeated = new String(new char[i]).replace("\0", decompress(compressedText.substring(1)));
            return repeated;
        }

    }
    //END SINGLE DIGIT

    //IF RIGHT PARENTHESIS
    if (compressedText.charAt(0) == ')')
    {
        if (compressedText.charAt(1) != ')')
        {
            System.out.println("8: " + compressedText);
            return "";
        }
        else
        {
            System.out.println("9: " + compressedText);
            return  decompress(compressedText.substring(1));

        }

    }
    //END 

        System.out.println("10: " + compressedText);
        return compressedText.charAt(0)+decompress(compressedText.substring(1));

}

最佳答案 我注意到的一件事是,当你输出“8:”后返回“”时,你“失去”了最后一个“a”.在那个位置上也应该处理尾随的字符,但是你不能简单地将它们归还 – 无论是直接还是通过解压缩它们 – 因为这会导致bbbabaabaababbbabaabaaba.

遗憾的是,我找不到基于你的代码的解决方案,它返回正确的值(我猜你将部分处理的文本放入递归中有一些奇怪的行为,但我不确定……).

但是,我想到了如何解决这个压缩问题,并想出了两个非递归解决方案.也许他们会帮助您改进解决方案.旁注:我的解决方案假设字符串格式正确,即它没有任何不匹配的括号等.
(我在答案结束时使用了重复功能.)

第一种解决方案使用正则表达式,该表达式搜索数字和后续部分(一个char或括号括起的部分,其中不包含括号本身).这样,括号和单焦点减压从内到外处理.

public static String decompressWithRegex(String s) {
    if ((s == null) || (s.length() == 0)) {
        return s;
    }
    // pattern for finding number with either bracket-enclosed, char-only part or single char
    Pattern p = Pattern.compile("(\\d+)((?:[^\\d\\(\\)]{1})|(?:\\([^\\d\\(\\)]+\\)))");
    String tmp = s;
    Matcher m = p.matcher(tmp);
    // start searching
    while (m.find(0)) {
        // first capture group returns count
        int count = Integer.parseInt(m.group(1));
        // second group is string to repeat (if it's bracket-enclosed, then remove brackets)
        String what = m.group(2).replace("(", "").replace(")", "");
        // build replacement part
        String replacePart = repeat(what, count);
        // replace it
        tmp = m.replaceFirst(replacePart);
        // reset matcher (source of matcher is now the new string)
        m.reset(tmp);
    }
    return tmp;
}

第二种解决方案不使用正则表达式.相反,它对如何处理解压缩做出了一些假设:

>任何未附有支架封闭部件的数字都可以直接使用
就地解压缩,这是先完成的
>通过找到第一个封闭支架来处理支架封闭部件
>然后从那里回来开始搜索开口括号
>这会让你重复一遍
>左边的开括号应该有一个数字然后被搜索和解析
>现在我们掌握了所有信息,更换部件已经建成并放置在正确的位置
>然后搜索下一个结束括号,如果有,则按上述方法处理
>如果没有右括号,则解压缩该字符串

码:

public static String decompressWithSearching(String s) {
    if ((s == null) || (s.length() == 0)) {
        return s;
    }
    // replace non-groups first
    for (int i = s.length() - 1; i >= 0; i--) {
        // find digit that is not followed by bracket
        if (Character.isDigit(s.charAt(i)) && s.charAt(i + 1) != '(') {
            // string to repeat is right behind the digit
            String part = s.substring(i + 1, i + 2);
            // find complete digit
            String countStr = "";
            int j = i;
            for ( ; j >= 0 && Character.isDigit(s.charAt(j)); j--) {
                countStr = s.charAt(j) + countStr;
            }
            int count = Integer.parseInt(countStr);
            // build replacement part
            String replacePart = repeat(part, count);
            // replace part
            s = s.substring(0, j + 1) + replacePart + s.substring(i + 2);
        }
    }

    // replace nested parts
    int closing;
    while ((closing = s.indexOf(')')) > -1) {
        // find matching opening bracket
        int opening = s.lastIndexOf('(', closing);
        // text between is to be repeated
        String what = s.substring(opening + 1,closing);
        // find complete digit
        String countStr = "";
        int numPartIndex = opening - 1;
        while (numPartIndex >= 0 && Character.isDigit(s.charAt(numPartIndex))) {
            countStr = s.charAt(numPartIndex) + countStr;
            numPartIndex--;
        }
        int count = Integer.parseInt(countStr);
        // build replacement part
        String replacePart = repeat(what, count);
        // replace part
        s = s.substring(0, numPartIndex + 1) + replacePart + s.substring(closing + 1);
    }

    return s;
}

重复字符串的实用方法:

public static String repeat(String what, int times) {
    if ((times <= 0) || (what == null) || (what.length() == 0)) {
        return "";
    }
    StringBuilder buffer = new StringBuilder(times * what.length());
    for (int i = 0; i < times; i++) {
        buffer.append(what);
    }
    return buffer.toString();
}
点赞