java:使用StringBuilder在开头插入

问题描述 投票:70回答:6

我只能用String执行此操作,例如:

String str="";
for(int i=0;i<100;i++){
    str=i+str;
}

有没有办法用StringBuilder实现这个目的?谢谢。

java string insert append stringbuilder
6个回答
157
投票
StringBuilder sb = new StringBuilder();
for(int i=0;i<100;i++){
    sb.insert(0, Integer.toString(i));
}

警告:它违背了StringBuilder的目的,但它完成了你的要求。


更好的技术(虽然仍然不理想):

  1. 反转要插入的每个字符串。
  2. 将每个字符串附加到StringBuilder
  3. 完成后反转整个StringBuilder

这将把O(n²)解变成O(n)。


26
投票

你可以使用strbuilder.insert(0,i);


11
投票

也许我错过了一些东西,但你想结束一个看起来像这样的字符串,"999897969594...543210",对吗?

StringBuilder sb = new StringBuilder();
for(int i=99;i>=0;i--){
    sb.append(String.valueOf(i));
}

6
投票

作为替代解决方案,您可以使用LIFO结构(如堆栈)来存储所有字符串,并在完成后将它们全部取出并将它们放入StringBuilder中。它自然地反转放置在其中的项目(字符串)的顺序。

Stack<String> textStack = new Stack<String>();
// push the strings to the stack
while(!isReadingTextDone()) {
    String text = readText();
    textStack.push(text);
}
// pop the strings and add to the text builder
String builder = new StringBuilder(); 
while (!textStack.empty()) {
      builder.append(textStack.pop());
}
// get the final string
String finalText =  builder.toString();

4
投票

这个线程很老了,但你也可以想一下递归StringBuilder的递归解决方案。这允许防止任何反向处理等。只需要通过递归设计迭代并仔细决定退出条件。

public class Test {

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        doRecursive(sb, 100, 0);
        System.out.println(sb.toString());
    }

    public static void doRecursive(StringBuilder sb, int limit, int index) {
        if (index < limit) {
            doRecursive(sb, limit, index + 1);
            sb.append(Integer.toString(index));
        }
    }
}

2
投票

当我偶然发现这篇文章时,我有类似的要求。我想要一种快速的方法来构建一个可以从双方增长的字符串,即。在正面和背面任意添加新字母。我知道这是一篇很老的帖子,但它激发了我尝试创建字符串的几种方法,我想我会分享我的发现。我也在使用一些Java 8构造,它可以优化案例4和5的速度。

https://gist.github.com/SidWagz/e41e836dec65ff24f78afdf8669e6420

上面的要点有详细的代码,任何人都可以运行。我在这方面采取了几种方法来增长; 1)附加到StringBuilder,2)插入StringBuilder的前面,如@Mehrdad所示,3)从StringBuilder的前面和末尾部分插入,4)使用列表从末尾追加,5)使用Deque来从前面追加。

// Case 2    
StringBuilder build3 = new StringBuilder();
IntStream.range(0, MAX_STR)
                    .sequential()
                    .forEach(i -> {
                        if (i%2 == 0) build3.append(Integer.toString(i)); else build3.insert(0, Integer.toString(i));
                    });
String build3Out = build3.toString();


//Case 5
Deque<String> deque = new ArrayDeque<>();
IntStream.range(0, MAX_STR)
                .sequential()
                .forEach(i -> {
                    if (i%2 == 0) deque.addLast(Integer.toString(i)); else deque.addFirst(Integer.toString(i));
                });

String dequeOut = deque.stream().collect(Collectors.joining(""));

我将专注于前面附加的情况,即。情况2和案例5. StringBuilder的实现在内部决定内部缓冲区如何增长,除了在前端附加限制速度的情况下从左到右移动所有缓冲区。直接插入StringBuilder前面所花费的时间增长到非常高的值,如@Mehrdad所示,如果需要只有长度小于90k字符的字符串(仍然很多),前插入将构建一个String,同时通过在末尾附加来构建相同长度的String。我所说的是时间惩罚确实会被踢出并且是巨大的,但只有当你必须构建非常庞大的字符串时。可以使用双端队列并在末尾连接字符串,如我的示例所示。但是StringBuilder的读取和编码更直观,对于较小的字符串,惩罚也无关紧要。

实际上,案例2的表现要比案例1快得多,我似乎并不理解。我假设StringBuilder中内部缓冲区的增长在前加法和后加法的情况下是相同的。我甚至将最小堆设置为非常大的数量,以避免延迟堆增长,如果这会起到作用。也许有更好理解的人可以在下面评论。

© www.soinside.com 2019 - 2024. All rights reserved.