如何减少代码的时间复杂度?

时间:2019-11-29 18:17:59

标签: string stack java-7

下面的Java代码是problem in Hackerrank的解决方案-一种简单的文本编辑器,具有4个操作(追加,删除,打印,撤消)。很少有测试用例超时,我无法对其进行进一步优化。 Java中的substring函数是O(n),我怀疑这是我需要改进的地方。请提供您的帮助。

    class Element {
    int operation;
    String str;
    Element(int op, String str) {
        this.operation = op;
        this.str = str;
    }
    }
    public class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for(int i=0; i<n; i++) {
            int step = sc.nextInt();
            if(step == 1) {
                String str = sc.next();
                append(str);
            } else if(step == 2 ) {
                delete(sc.nextInt());
            } else if(step == 3) {
                print(sc.nextInt());
            } else {
                undo();
            }
        }
    }

    public static void append(String str) {
        stack.push(new Element(1, file));
        file+= str;

    }

    public static void delete(int k) {
        stack.push(new Element(2, file));
        file = file.substring(0, file.length() - k);
    }

    public static void print(int k) {
        System.out.println(file.charAt(k-1));
    }

    public static void undo() {
        if(stack.size() == 0) {
            return;
        }
        Element e = stack.pop();
        file = e.str;
    }

    public static String file = "";
    public static Stack<Element> stack = new Stack<>();
    }

1 个答案:

答案 0 :(得分:1)

一件事将为您节省大量内存,而不是将整个字符串压入撤消堆栈,而只是推动反向操作。考虑一下,您有两个修改字符串的操作:一个追加,以及从字符串中删除最后一个 k 个字符。

append的反向是删除,而delete的反向是追加。

因此,当您处理一个附加命令时,您执行的撤消操作可以是:

push(2, length-of-string)

编写撤消堆栈的方式,必须将长度保存为字符串,但这并不困难。

当您处理删除命令时,您执行的撤消操作是:

push(1, file.substring(k))

您的撤消操作,然后执行您从堆栈中弹出的操作。

这应该为您节省大量内存,这意味着垃圾收集器不必这么辛苦地工作,因此它应该更快。

我仍然认为您应该考虑StringBuilder。问题中的约束说明所有字符串的总长度小于或等于106,这意味着您可以将StringBuilder预先分配为1兆字节,而不必为它重新分配空间。另外,附加和删除操作可以就地完成,而不是强制每个操作都分配和复制新的String实例。使用String,每次您编写类似file = file + str;的内容时,会发生以下情况:

  1. 为新的String实例分配了内存以保存修改后的值
  2. 将现有字符串复制到该新内存中
  3. str已添加

所有这一切都需要时间,还需要练习垃圾回收器。与StringBuilder(已经分配了内存)进行对比。因此,在附加操作上要做的就是将新字符串复制到缓冲区中。删除后,您可以设置长度,如下所示:

sb.setLength(sb.length() - k); // assuming your StringBuilder is called sb

在使用StringBuilder和对撤消堆栈进行优化之间,您的代码应该要快得多。