下面的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<>();
}
答案 0 :(得分:1)
一件事将为您节省大量内存,而不是将整个字符串压入撤消堆栈,而只是推动反向操作。考虑一下,您有两个修改字符串的操作:一个追加,以及从字符串中删除最后一个 k 个字符。
append的反向是删除,而delete的反向是追加。
因此,当您处理一个附加命令时,您执行的撤消操作可以是:
push(2, length-of-string)
编写撤消堆栈的方式,必须将长度保存为字符串,但这并不困难。
当您处理删除命令时,您执行的撤消操作是:
push(1, file.substring(k))
您的撤消操作,然后执行您从堆栈中弹出的操作。
这应该为您节省大量内存,这意味着垃圾收集器不必这么辛苦地工作,因此它应该更快。
我仍然认为您应该考虑StringBuilder
。问题中的约束说明所有字符串的总长度小于或等于106,这意味着您可以将StringBuilder
预先分配为1兆字节,而不必为它重新分配空间。另外,附加和删除操作可以就地完成,而不是强制每个操作都分配和复制新的String
实例。使用String
,每次您编写类似file = file + str;
的内容时,会发生以下情况:
String
实例分配了内存以保存修改后的值str
已添加所有这一切都需要时间,还需要练习垃圾回收器。与StringBuilder
(已经分配了内存)进行对比。因此,在附加操作上要做的就是将新字符串复制到缓冲区中。删除后,您可以设置长度,如下所示:
sb.setLength(sb.length() - k); // assuming your StringBuilder is called sb
在使用StringBuilder
和对撤消堆栈进行优化之间,您的代码应该要快得多。