编写返回String的方法 getLargeAndSmallLetters 包含以下所有大写和小写ASCII字母 形式(由空格分隔的大写和小写字母,字母 用逗号分隔的组,最后没有逗号):
a a,B b,C c,D d,E e,...,Z z
算法规范没有详细说明实现细节,即StringBuilder
结构的使用,算法必须满足的效率指南或任何有关实现可读性的最佳实践。
我编译并返回所需输出的算法版本
public static String getLargeAndSmallLetters() {
StringBuilder builder = new StringBuilder();
for (int i = 64; i < 96; ++i) { // WRONG: hard coded
if (Character.isLetter(i)) {
String upper = Character.toString((char)i);
String lower = Character.toString((char)(i+32));
builder.append(upper + " " + lower + ", "); // WRONG: in loop
}
}
String result = builder.toString();
result = result.substring(0, result.length() - 2);
return result;
}
我的讲解员可能希望看到的是这样的for
循环
for (char lower = 'a'; lower <= 'z'; ++lower) {
Character upper = Character.toUpperCase(lower);
builder.append(upper)
.append(" ")
.append(lower)
.append(", ");
}
为什么算法会在学术上成为&#34;这样更正确吗?这也可以通过简单的字符串连接来解决。
我首先想了解为什么我的解决方案不是最佳(但正确 IMO)。拥有C#背景,并且只能粗略地猜测为什么我的代码不是最佳的原因:
for
循环经历了太多次迭代。我纠正了这个丑陋的&#34;但使用if (Character.isLetter(i))
的正确方法。int
转换为char
s。是否会发生任何影响性能的拳击/拆箱? String
的方式,我是通过在我的String
内使用+
运算符的字符串连接在字符串池中创建更多不可变for
的环?使用StringBuilder
会更有效率,因为它会在内部更有效地重用" "
和", "
String
吗?现在我还想做的是提供一个&#34;学术论点&#34;这证明了我答案的正确性。这里有一些想法:
选项3似乎是证明我的答案正确性的最直接的方式。
对于选项1和2,我认为我需要将for循环更正为for (int i = 65; i < 91; ++i)
并删除if (Character.isLetter(i))
语句。
我将非常感谢您对我的想法的任何建议,补充和更正。
答案 0 :(得分:1)
编译器优化了我的错误&#34;离开并实际为&#34;错误&#34;生成相同的字节代码。并且&#34;纠正&#34;答案
不,编译器通过优化来非常少。它可能会将您的某些字符串连接更改为StringBuilder
appends
,但这是关于它的;否则,只需忠实地以字节码形式再现您在代码中编写的内容。基本上所有的智能都发生在JIT中。
您可以很容易地看到他们不会生成相同的字节码:使用javap -c <YourClass>
对其进行反编译。
JIT编译器为&#34;正确&#34;执行相同的机器代码。并且&#34;错误&#34;回答实施
JIT最终会执行代码。对于这样的事情,它可能会执行一次,因此不值得JIT&#39。
但我强烈怀疑JIT会为这两种方法生成相同的代码,因为这两种方法完全不同。
提供算法正确性的数学证明
Java的正式证明很难。在证明中你必须考虑到许多微妙的语义;或者,至少证明那些语义不涉及代码的执行。
你所能做的就是断言它在功能上是等价的。如同,不能证明它是正确的,但证明它不正确。
为此编写测试非常容易,因为您知道正确的输出:
A a, B b, C c, ...
因此,请检查您的代码是否产生了该代码,并且您已完成。或者,当然,检查您的代码是否产生与模型答案相同的输出。
您的答案实际上与模型答案完全相同。你从最后砍掉了,
;模型答案没有。
答案 1 :(得分:1)
你正在打一场失败的战斗。如果您的“docent”无法检查您的代码是否产生正确的输出,那么他就不会费心去阅读算法正确性的证明。如果你从中学到一件事,那就是你经常要遭遇傻瓜,所以要善于做。
也就是说,通过显示(a)它不接受任何输入(b)它不受副作用的影响(更现实地,不是那些也不影响你的讲解员解决方案的那些),可以证明代码的正确性。然后通过显示(c)算法的实际执行跟踪得出正确的输出(正确的是它产生与你的讲师相同的东西)来结束。
鉴于此,没有充分的理由选择一种实施方式。如果您更喜欢性能,简洁或优雅的模型答案,那么这个问题的解决方案比您或您的医生找到的更好,更简单:
public static String getLargeAndSmallLetters() {
return "A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y, Z z";
}
你可以使它更具可读性:
public static String getLargeAndSmallLetters() {
return String.format("%s%s",
"A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, ",
"N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y, Z z");
}
注意:for
- 循环遍历char
是非常糟糕的,你不应该这样做。我不能说我的同事在他的代码中尝试了这一点,但如果那一天到来,我会感谢同行代码审查。