【问题标题】:Expansion on given string according to number * contents of the parentheses根据括号的数字 * 内容扩展给定字符串
【发布时间】:2021-02-28 13:33:42
【问题描述】:

我正在尝试获取给定的字符串,当括号前有一个数字时,括号内的内容会重复该次数。我考虑过使用 StringBuilder 并构建了这个函数,但我不确定如何重复括号的内部。 示例- 3(ab) - 结果为 ababab ,示例- 3(b(2(c))) 结果为 bccbccbcc 在我在这里构建的函数中,它重复括号而不是括号的内容。

  public static String solve(String s){
    StringBuilder sb = new StringBuilder();
    int repeat = 0;
    for (char c : s.toCharArray()) {
        if (Character.isDigit(c)) {
            repeat = repeat * 10 + Character.getNumericValue(c);
        } else {
            while (repeat > 0) {
                sb.append(c);
                repeat--;
            }
            sb.append(c);
        }
    }
    return sb.toString();
    }
}

【问题讨论】:

  • 这里有点棘手的部分是找到匹配的括号。最简单的方法可能是使用多次传递,其中每次传递仅在下一个关闭括号之前替换没有左括号的部分。当没有更多的括号时,您可以停止,或者您发现语法错误(例如,只剩下一个括号)
  • 括号前面的数字是否始终为单个数字,或者12(b) 也是有效输入?并且数字也可以出现在括号前面以外的其他地方吗?例如3(a4b)?
  • 输入将仅包含有效括号中的小写字母和数字(1 到 9)。最后一个右括号后没有字母或数字。
  • 就上下文而言,更一般的任务称为解析,或构建parse treesyntax tree (wikipedia)。有这方面的库,但对于您相对简单的语法来说,它们可能有点矫枉过正。构建树形结构可以让您一次性完成此操作。 (您不需要实际创建树,但考虑递归方法会有所帮助)。
  • 括号前面的字母怎么样,比如你的第二个例子:3(b(2(c)))=>3(b(cc))

标签: java string algorithm stringbuilder expansion


【解决方案1】:

您需要一个堆栈来维护从最内层到最外层容器所需的操作的某种内存。

这是 Python 中的代码:

def parenthesis_printer(s):
    L = [""]   # maintains the stack of the string-containers
    N = [1]    # maintains the stack of the print-multiplier needed for the corresponding string-container
    nstr = ""
    for i in range(len(s)):
        if s[i].isnumeric():
            nstr += s[i]
        elif s[i] == '(':
            nstr = "1" if len(nstr) == 0 else nstr
            nval = int(nstr)
            N.append(nval)
            L.append("")
            nstr = ""
        elif s[i] == ')':
            nval = N.pop()
            lval = L.pop()
            lstr = "".join([lval for _ in range(nval)])
            L[-1] += lstr
        else:
            L[-1] += s[i]
    return L[-1]

print(parenthesis_printer("3(b(2(c)))"))

输出:

bccbccbcc

【讨论】:

  • 这个想法很容易转移到Java。逻辑保持不变。
  • 是N个和L个字符串还是一个字符串数组?
  • 每个循环在哪里结束?
  • N 和 L 是堆栈。 N 维护数字乘数,L 维护相应容器中的字符串
  • 所以栈不是stringbuilder?
【解决方案2】:

问题自然是递归的。保留您已经开始的方法,您可以编写如下内容。在实际代码中,我可能更喜欢将标记化和解析分开的方法,这意味着我会做两次单独的传递:第一次将输入字符串转换为标记,第二次从标记流产生输出。

public static Pair<String, Integer> solve(String s, int start) {
    int repeat = 0;
    String ret = "";

    for (int i = start; i < s.length(); i++) {
        final char c = s.charAt(i);

        if (Character.isDigit(c)) {
            repeat = repeat * 10 + Character.getNumericValue(c);
        } else if (c == '(') {
            final Pair<String, Integer> inner = solve(s, i + 1);
            // At least one repetition, even if no explicit `repeat` given.
            ret += inner.first;
            while (--repeat > 0) {
                ret += inner.first;
            }
            repeat = 0; // Ensure that `repeat` isn’t -1 after the loop.
            i = inner.second;
        } else if (c == ')') {
            return new Pair<>(ret, i);
        } else {
            ret += c;
        }
    }

    return new Pair<>(ret, s.length());
}

将此代码转换为使用单个 StringBuilder — 以避免多余的字符串副本 — 留作练习。


上面使用了一个简单的Pair 辅助类。由于 Java 没有附带 (groan),因此这里有一个非常简单的实现,可以与上述代码并列;你也可以使用 JavaFX 的 javafx.util.Pairjava.util.AbstractMap.SimpleEntry 或其他。

static class Pair<T, U> {
    final T first;
    final U second;

    Pair(T f, U s) {
        first = f;
        second = s;
    }
}

【讨论】:

  • 我尝试使用导入,但似乎在 Eclipse 上给了我错误
  • @rokkcrow 什么错误?您是如何尝试使用它的?
  • 我复制了import和import javafx.util.Pair;在上课之前,它给了我错误,当我输入代码时,它不是导入选项之一
  • @rokkcrow 再说一遍,什么错误? 你使用的是什么 Java 版本? (JavaFX 已在 Java 11 中删除,但还有其他直接的方法可以替换 Pair 类。)
  • 我正在使用 Eclipse IDE
【解决方案3】:

@SerialLazers 的答案几乎相同,但在 java 中并带有一些调试输出以查看代码的行为:

public static String solve(String s)
{
    Stack<Integer> countStack = new Stack<>();   // stack for counting
    Stack<StringBuilder> stubs = new Stack<>();  // stack for parts of the string that were processed
    stubs.push(new StringBuilder());
    
    int count = 0;
    for(char c : s.toCharArray())
    {
        System.out.println(Character.toString(c) + "   " + count + "   " + countStack + stubs);
        
        if(Character.isDigit(c))
        {
            // part of a count (assumes digits are never part of the actual output-string)
            count = count * 10 + (c - '0');
        }
        else if(c == '(')
        {
            // encountered the start of a new repeated group
            if(count == 0)
                // no count specified, assume a count of one
                countStack.push(1);
            else
                // push the count for this group
                countStack.push(count);

            // push a new stringbuilder that will contain the new group
            stubs.push(new StringBuilder());
            count = 0;  // reset count
        }
        else if(c == ')')
        {
            // group terminated => repeat n times and append to new group one above
            String tmp = stubs.pop().toString();
            int ct = countStack.pop();
            
            for(int i = 0; i < ct; i++)
                stubs.peek().append(tmp);
        }
        else
        {
            // just a normal character, append to topmost group
            stubs.peek().append(c);
            count = 0;
        }
    }
    
    // if the string was valid there's only the output-string left on the stubs-list
    return stubs.peek().toString();
}

输出:

3   0   [][]
(   3   [][]
b   0   [3][, ]
(   0   [3][, b]
2   0   [3, 1][, b, ]
(   2   [3, 1][, b, ]
c   0   [3, 1, 2][, b, , ]
)   0   [3, 1, 2][, b, , c]
)   0   [3, 1][, b, cc]
)   0   [3][, bcc]

返回:

bccbccbcc

【讨论】:

  • 以这种方式创建大量新的字符串构建器是货物崇拜编程;它实际上比使用字符串连接效率
  • 好的。我试过了,但在这个例子中预期: 但是是: 有没有办法不删除 [] 的内容,我认为它来自你使用的 pop 函数
  • 给定:4(1(5b(n(j)))) 输出:bnjbnjbnjbnj 预期输出:bnjbnjbnjbnj[bnjbnjbnjbnjbnjbnjbnjbnjbnjbnjbnjbnjbnjbnjbnjbnj]
  • @Paul 请在上方查看
  • @KonradRudolph 好吧,通常情况下,该代码旨在展示一个原则,而不是作为最高效的解决方案。有很多点可以优化,但至少 IMO 可读性优于性能
猜你喜欢
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
  • 1970-01-01
  • 2016-08-19
  • 2018-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多