这很可能是 Java 中最有效的实现:
public static boolean isP(String s) {
char[] chars = s.toCharArray();
for (int i = 0; i < (chars.length / 2); i++) {
if (chars[i] != chars[(chars.length - i - 1)])
return false;
}
return true;
}
好处:
- 第一眼看到差异就返回。
使用直接 char[] 访问来避免在 charAt 中进行的边界检查
- 仅迭代一半字符串,而不是完整字符串。
与所有其他提议的解决方案一样,它仍然是 O(N)。
我刚刚测量了一个非常大的字符串的所提供解决方案的时间(以纳秒为单位的时间):
Aran: 32244042
Andreas: 60787894
Paul Tomblin: 18387532
首先,上述测量是使用客户端 VM完成的。因此,计算i < (chars.length / 2)
没有作为常数内联。使用 -server Vm 参数可以得到更好的结果:
Aran: 18756295
Andreas: 15048560
Paul Tomblin: 17187100
驱动它有点极端:
首先警告一句:请勿在您打算使用/运输的任何程序中使用此代码。
正如评论中所指出的,它包含隐藏的错误并且不遵守 Java API并且没有错误处理。它纯粹是为了证明通过肮脏的技巧可以获得的理论性能改进。
从字符串复制数组时会有一些开销,因为字符串类在内部进行了防御性复制。
如果我们直接从字符串中获取原始的 char[],可以挤出一点性能,代价是对字符串使用反射和 unsave 操作。这使我们的性能又提高了 20%。
public static boolean isPReflect(String s) {
char[] chars = null;
try {
final Field f = s.getClass().getDeclaredField("value");
f.setAccessible(true);
chars = (char[]) f.get(s);
}
catch (IllegalAccessException e) {
}
catch (NoSuchFieldException e) {
}
final int lenToMiddle = chars.length / 2;
for (int i = 0; i < lenToMiddle; i++) {
if (chars[i] != chars[(chars.length - i - 1)])
return false;
}
return true;
}
时间:
Aran: 18756295
Andreas1: 15048560
Andreas2: 12094554
Paul Tomblin: 17187100