有没有一种方法可以比O(n)更快地反转字符串?

时间:2020-04-03 21:38:51

标签: java string performance optimization big-o

我有以下代码,用参数-Xmx<1024M>运行需要5秒钟以上。

我知道for循环需要O(q)时间,而reverse()toString()分别需要O(n)时间。

是否有一种方法可以在不到O(n)的时间内反转字符串?还是其他原因使代码速度变慢?任何帮助都将受到欢迎!

class Main {
  public static void main(String[] args){
    String s = "a";
    String qa = "200000";
    int q = Integer.parseInt(qa);
    String[] t = new String[q];
    for(int i = 0; i < q; i++) {
      if(i%2==0) {t[i] = "2 1 x";}
      if(i%2==1) {t[i] = "1";}
      if(t[i].toCharArray()[0] == '1') {
        StringBuilder rev = new StringBuilder(s).reverse();
        s = rev.toString();
      } else {
        char letter = t[i].toCharArray()[4];
        if(t[i].toCharArray()[2] == '1') {
          s = letter + s;
        } else {
          s = s + letter;
        }
      }
    }
    System.out.println(s);
  }
}

2 个答案:

答案 0 :(得分:4)

不管应该做什么(我不知道),我发现了以下问题:

  • 每次迭代中StringBuilder的多个实例化。
  • 使用+运算符的字符串连接。
  • 重复使用Sring::toCharArray(请参阅第二种解决方案)

仅使用StringBuilder的一个实例,您将获得更快的结果:

String s = "a";
String qa = "200000";
int q = Integer.parseInt(qa);
String[] t = new String[q];
StringBuilder sb = new StringBuilder(s);       // Instantiate before the loop
for (int i = 0; i < q; i++) {
    if(i%2==0) {t[i] = "2 1 x";}
    if(i%2==1) {t[i] = "1";}
    if(t[i].toCharArray()[0] == '1') {
        sb.reverse();                          // all you did here is just reversing 's'
    } else {
        char letter = t[i].toCharArray()[4];
        if(t[i].toCharArray()[2] == '1') {
            sb.insert(0, letter);              // prepend a letter
        } else {
            sb.append(letter);                 // append a letter
        }
    }
}

另一件事是,您多次定义了诸如t[i] = "2 1 x";之类的字符串,然后将其与t[i].toCharArray()[0]进行比较。预先定义这些不可变的值,使用char[][]也会有所帮助:

String s = "a";
String qa = "200000";
int q = Integer.parseInt(qa);
char[][] t = new char[q][];                    // char[][] instead of String[]
char[] char21x = new char[]{'2', '1', 'x'};    // predefined array
char[] char1 = new char[]{'1'};                // another predefined array
StringBuilder sb = new StringBuilder(s);       // Instantiate before the loop
for (int i = 0; i < q; i++) {
    if(i%2==0) {t[i] = char21x;}     // first reuse
    if(i%2==1) {t[i] = char1;}       // second reuse
    if(t[i][0] == '1') {             // instead of String::toCharArray, mind the indices
        sb.reverse();                // all you did here is just reversing 's'
    } else {
        char letter = t[i][2];       // instead of String::toCharArray, mind the indices
        if(t[i][1] == '1') {
            sb.insert(0, letter);    // prepend a letter
        } else {
            sb.append(letter);       // append a letter
        }
    }
}

编辑:我已经使用笔记本电脑上的System.currentTimeMillis()进行了最简单的测试:

  • 原始解决方案:7.6586.8997.046
  • 第二个解决方案:3.2883.6913.158
  • 第三种解决方案:2.7172.9662.717

结论:我认为无法从算法复杂度方面改善算法本身,但是,使用正确的方法处理String有助于将时间复杂度降低2-3倍(在我看来情况)。

一般建议:您可以在循环之前实例化和定义什么,在循环之前进行。

答案 1 :(得分:-1)

有没有一种方法可以在不到O(n)的时间内反转字符串?还是其他原因使代码速度变慢?

没有办法在少于O(n)的时间内反转字符串:产生大小为n的输出的程序必须最少花费o(n)的时间。

您的代码中有许多不必要的操作,这些操作会使程序变慢。该程序产生50000个字母x,然后是一个字母a,然后是另一个50000个字母x。这是同一程序的更快(更容易理解)的实现。

class Faster {
    public static void main(String[] args) {

        String hundredXs = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

        for (int i = 0; i < 500; i++)
            System.out.print(hundredXs);

        System.out.print("a");

        for (int i = 0; i < 500; i++)
            System.out.print(hundredXs);

        System.out.println();
    }
}
相关问题