使用递归如何压缩字符串?(RLE算法)

4

我在尝试使用递归压缩字符串时遇到了些许困难。

例如,考虑以下字符串:

qwwwwwwwwweeeeerrtyyyyyqqqqwEErTTT

应用RLE算法后,该字符串转换为:

q9w5e2rt5y4qw2Er3T

在压缩后的字符串中,“9w”代表连续的9个小写字母“w”。 “5e”表示连续的5个小写字母“e”,以此类推。

我已经有一个不使用递归的压缩代码:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Compress {

    public static String input(String source) {
        StringBuffer coding = new StringBuffer();
        for (int i = 0; i < source.length(); i++) {
            int runLength = 1;
            while (i+1 < source.length() && source.charAt(i) == source.charAt(i+1)) {

                runLength++;   

                i++;

           }
            if (runLength>1){
            coding.append(runLength);
            }
            coding.append(source.charAt(i));
        }
        return coding.toString();
    }

    public static void main(String[] args) {

        IO.outputStringAnswer("Enter a string");
        String str = IO.readString();
        String result = ""; 
        result=input(str); //function(variable)


        IO.outputStringAnswer(result);
    }
}

但我不确定这是否能够转换为递归版本。


3
当然可以编写一个递归版本,但这样做没有明显的好处。 - Jim Mischel
3
为什么要使用递归来压缩字符串?我很难想象在Java中这样做的理由。 - Vegard
哦,这是我需要完成的任务的一部分,但我之前从未在任务中使用过递归,直到现在。我查找了一些示例,但似乎无法弄清如何将递归用于压缩。 - AChoi
1
这个任务提供了使用递归的任何指导或理由吗?这似乎是递归的一个非常糟糕的应用。 - Jim Garrison
哦,哇,我完全读错了任务哈哈。他们给了我一个方法文件,所以我只需要完成它。我现在认为我大致知道该怎么做了,不过还是谢谢你的评论^^ - AChoi
显示剩余2条评论
2个回答

5
这很可能是你正在寻找的内容:
public static String compress(String source) {
    if (source.length() <= 1) return source;

    int runLength = 1;
    while (runLength < source.length() && source.charAt(0) == source.charAt(runLength)) {
        runLength++;
    }

    String lengthString = runLength > 1 ? String.valueOf(runLength) : "";
    return lengthString + source.substring(0,1) + compress(source.substring(runLength));
}

我假设您的源字符串不包含任何数字。如您所见,该函数在最后一行使用源字符串的余数进行递归调用。


3

这是一个有趣的问题。一种不使用迭代,只使用递归的解决方案如下:

public static String compressRecursion(String str, char curChar, int curCount) {
    // termination case - reached end of the source string
    if(str.length() == 0)
        return "" + (curCount == 1 ? "" : curCount) + curChar;

    // branch on change in next character
    String nextStr = str.substring(1,str.length());
    if(str.charAt(0) == curChar)
        return compressRecursion(nextStr,curChar,curCount + 1);
    else
        return "" + (curCount == 1 ? "" : curCount) + curChar
                + compressRecursion(nextStr,str.charAt(0),1);
}
public static String compress(String source) {
    return compressRecursion(source, source.charAt(0), 0);
}

这在实际应用中可能没有太大价值,因为输入任何合理长度的内容都会导致“堆栈溢出”异常,这是因为每次函数调用和输入字符时都会创建一个新的堆栈帧。Java不是专为运行此类代码而设计的。
在 Scheme 中编写一个同义压缩函数(它没有迭代构造)。
(define (num2str num)
  (if (= 1 num) "" (number->string num)))

(define (first-char str)
  (substring str 0 1))

(define (next-string str)
  (substring str 1 (string-length str)))

(define (compress str char count)
  (cond [(= 0 (string-length str)) (string-append (num2str count) char)]
        [(string=? char (first-char str))
          (compress (next-string str) char (+ count 1))]
        [ else 
          (string-append (num2str count) char
            (compress (next-string str) (first-char str) 1))]))

(define (compressStart str)
  (compress str (first-char str) 0)) 

像 Scheme 这样的函数式语言会使用尾递归优化来防止堆栈溢出,并使函数调用比 Java 这样的命令式语言更轻量级。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接