这篇文章的目的是收集所有可以轻松应用的高尔夫球技巧,<all languages>
而不是特定的技巧。
仅发布其逻辑可应用于大多数语言的答案
请给每个答案一个提示
<all languages>
...
这篇文章的目的是收集所有可以轻松应用的高尔夫球技巧,<all languages>
而不是特定的技巧。
仅发布其逻辑可应用于大多数语言的答案
请给每个答案一个提示
<all languages>
...
Answers:
通常,您可以将两个后续循环或两个嵌套循环合并为一个。
之前:
for (i=0; i<a; i++) foo();
for (i=0; i<b; i++) bar();
后:
for (i=0; i<a+b; i++) i<a?foo():bar();
foo
称为a
时间,bar
称为b
时间。这是因为在“之后”中,循环运行a+b
时间,即第一个a
调用foo
,下一个调用bar
。
for(y=0;y<Y;++y)for(x=0;x<X;++x)
能经常成为for(i=0;i<X*Y;++i)
与x
取代i%X
和y
被取代i/X
。
仅提及显而易见的一点:
打高尔夫球时(尤其是较难的问题导致更长的程序),您可能会经常选择最初选择的路线而无需尝试其他基本选择。当然,您可能一次只打一条或几条线,也可能只是整体思路的一部分,但通常不尝试完全不同的解决方案。
这在Hitting 495(Kaprekar)中尤其明显,在许多语言中,它偏离实际算法并寻找可用于获得相同结果的模式,这在许多语言中都比较短(只是J语言)。
不利的一面是您可能会多次解决同一件事。但是它几乎可以在除HQ9 +之外的所有语言中使用(在该语言中,找到另一种输出Hello World的方法会有些徒劳)。
如果代码必须处理各种输入,则编写全面的测试,并轻松快速地运行它们。这样一来,您就可以一次尝试一次冒险转换一次。打高尔夫球就变得像有错误意图的重构。
例如,如果A
和B
是布尔值,并且您的语言在某种程度上将布尔值像数字一样对待,A and (not B)
并且A>B
是等效的。例如在Python中
if A and not B:
foo()
是相同的:
if A>B:
foo()
B>A or foo()
这将是表达这种情况的更短的方法,利用对布尔表达式的惰性求值以确保仅在需要时才计算事物。
B>A or foo
将评估foo
是否B==A
不是我们想要的。(对吗?)
而不是x=1
尝试查找已经等于1
的值。例如,函数的返回值:printf("..");x=0;
-> x=!printf("..");
。最简单的是0,因为您总是可以取反,或者当您只需要正确的真值时(不必关心它是1还是19)。
了解您所用语言中空格的规则。某些标点符号或其他字符可能不需要任何周围的空格。考虑以下Bourne shell函数:
f () { echo a; echo b; }
在Bourne shell中,();
是元字符,不需要周围的空格。但是,{}
是单词,需要空格,除非它们在元字符旁边。我们可以打高尔夫球旁边的4个空间();
,但是必须保持在{
和之间的空间echo
。
f(){ echo a;echo b;}
在Common Lisp和PicoLisp中,()
是元字符。考虑以下代码以查找两个数字的平均值:
(/ (+ a b) 2)
我们可以打2个球。
(/(+ a b)2)
有些语言对空格有奇怪而微妙的规则。考虑一下这个Ruby程序,该程序输出整数行的和和乘积。
#!ruby -an
i=$F.map &:to_i
puts"#{i.reduce &:+} #{i.reduce &:*}"
每个人&
在自己之前都需要一个空间。在Ruby中,i=$F.map &:to_i
表示i=$F.map(&:to_i)
在何处&
传递block参数。但是,i=$F.map&:to_i
表示二进制运算符i=$F.map.&(:to_i)
在哪里&
。
这种怪异现象发生在使用歧义标点的语言(例如Perl或Ruby)中。如有疑问,请使用REPL或编写简短的程序来测试空白规则。
x = SomeLongFunctionName
x(somedata)
x(somemoredata)
etc
x
。
条件运算符
bool ? condition_true : condition_false
就字符而言,比IF 语句更有益。
if(a>b){r=a;}else{r=b;}
可以写成
r=a>b?a:b;
a&&b||c
代替使用。稍长,但仍比短if
。
Iff
,尽管它是一个功能,所以需要评估所有参数。
if(a ? b : c)
a&&b||c
可以返回c
的时候a
是真的当且仅当b
是假的,稍胜一筹的情况下,但是我们不应该忘记,^^
编写说明会迫使您再次彻底查看代码的每个部分,并在明确编写某些段落时表达您的想法和选择。这样做时,您可能会发现可以使用不同的方法来节省一些字节,或者您下意识地做出了不一定成立的假设。
这个技巧类似于询问您选择的算法并尝试全新的东西 ; 但是,我发现,实际写下每个部分的工作方式有时对于了解替代品至关重要。
另外,包括解释在内的答案对于其他用户而言也更有趣,因此更有可能被接受。
听起来很容易,但是通过小心一点,您可能根本不执行任何操作来“保存”一些字符!
如果您使用的是Windows,则可能会输入\r\n
而不是仅输入内容,\r
或者\n
当您按Return键时-每行增加一个额外的字节!转动控制字符只是为了再次检查您是否没有这样做。
在Notepad ++中\r\n
,只需\r
转到即可将所有行尾转换为Edit > EOL Conversion > UNIX/OSX Format
。
另外请确保您的字符数中不包含任何结尾的空格!代码最底行的换行符也无关紧要,因此也无需计数。
打高尔夫球的代码与理解问题(即使在任何其他情况下会暗示什么是问,什么不是问题)一样,与产生(可能)满足要求的代码一样重要。
除了明确要求的输入外,无需处理任何其他输入。如果存在一些测试用例,并且没有一般性要求,则您的代码仅在这些情况下可用。等等。
可能会有些优势,但有时可能会派上用场。它依赖于以下事实:m = 2 n -1应用于的所有数字的最右边n位设置为1。
所以,7 10 == 00000111 2,15 10 == 00001111 2,31 10 == 00011111 2等。
诀窍是x&~m
。每当这将返回true x
是不是介于0 m
(含),否则为false。它从下一个最短的等价表达式保存6个字节x>=0&&x<=m
,但显然仅在m
满足2 n -1时有效。
大于/小于保存数字:
//use:
if(n>9){A}else{B}
//instead of:
if(n<10){B}else{A}
只要记住将代码从交换if
到else
,它们将做完全相同的事情(或切换不等式的一面)!
注意:这可以应用10的任何幂及其负数:...-100, -10, 10, 100...
if(n>99999)
vsif(n<1e5)
如果通过循环运行以检查一个或多个布尔检查实例,则可能会使更高效的程序在第一个true值上退出循环。但是,删除中断和循环遍历所有迭代可以缩短代码。
int main() {
bool m = false;
int n = 1000;
for (int i = 0; i < n; i++) {
if (i >= 100) {
m = true;
break; // remove this line
}
}
return 0;
}
if
在以下情况下,您还可以简化语句:m|=i>=100
。(在这种情况下,您也可以简化i>=100
为i>99
,但是在这里不是很重要)
大多数语言都有一种方法可以将某种形式的令牌周围的字符串拆分为字符串数组。一旦长度达到与语言相关的阈值,这将不可避免地比数组文字短,因为每个字符串的额外开销将是一个1字符令牌的一个副本,而不是(至少)两个字符串定界符。
例如,在GolfScript中
["Foo""Bar""Baz""Quux"] # 23 chars
变成
"Foo
Bar
Baz
Quux"n/ # 20 chars
对于某些语言,阈值低至一个字符串。例如,在Java中,
new String[]{"Foo"} // 19 chars
变成
"Foo".split("~") // 16 chars
%w{Foo Bar Baz Quux}
。
qw(Foo Bar Baz Quux)
成为字符串列表。
如果您有X
报表{
里面}
的for循环,您可以将X-1
报表(
中)
的第二个分号后的for循环for(blah;blah;HERE)
,以节省3个字节。(使用逗号分隔语句,
)
代替
for(int i=0;i<9;){s+=s.length();println(i++);}
您可以将其中一个语句移到for循环的(
大括号中,)
而将另一个移出
for(int i=0;i<9;println(i++))s+=s.length();
并保存3个字节(由于@ETHProductions而又节省了1个字节)
简单地说,
代替
for(blah;blah;){blah 1;blah 2;...;blah X}
移动语句,以便最终得到这个
for(blah;blah;blah 2,...,blah X)blah 1;
并保存3个字节
for
是最后陈述时,;
变成可选
~
用于a-b-1
和a+b+1
除了@Lynn关于x+1
→ 的建议之外-~x
;和x-1
→~-x
,您也可以打高尔夫球a-b-1
和a+b+1
。
a-b-1 // 5 bytes
a+~b // 4 bytes
a+b+1 // 5 bytes
a-~b // 4 bytes
似乎您不会经常使用的技巧,有点像使用~x
而-x-1
不是经常发生的技巧,但是我已经使用了足够的时间,在这里将其视为有用的技巧。特别是在使用数组索引的情况下,您可能会在某些情况下使用以上这些。
当试图挤压由ands(或ors,在这种情况下,只用“ any”代替“ all”)链接的条件时,我想到了一个简单的技巧。
例如:
if a>0 and a<10 and a+b==4 and a+3<1:
成为
if all([a>0,a<10,a+b==4,a+3<1]):
all(array-of-Booleans)
内置功能?
[a>0,a<10,a+b==4,a+3<1].all?
if 10>a>0 and a+b==4>1>a+3:
确保知道编译器可以保证哪些优化以及在哪些优化级别可以自由使用它们。即使业绩并不关心要求,您仍然可以在最佳化测试,然后只贴一个字符,因为你的代码仍然是技术上没有编译器标志有效。
考虑以下Haskell函数来计算2 ^ n(忽略Haskell已经具有内置的幂运算符或三个幂)(23个字符):
p 0=1;p x=p(x-1)+p(x-1)
问题是-速度太慢了,它以指数速度运行。这可能会使您的代码不可测试,或者无法解决问题给出的任何性能限制。您可能会想使用临时变量或立即调用的函数文字以避免重复的函数调用(25个字符):
p 0=1;p x=(\y->y+y)$p$x-1
但是编译器已经可以为您做到这一点,您只需要将其设置-O
为编译器标志即可!不必告诉每个站点几个额外的字符来手动消除常见的子表达式,只需告诉编译器为您做基本优化,整个程序中总共可以包含一个或两个字符。
p(x-1)*2
吗?
也许有些明显,但是...
请记住,赋值运算符返回一个值!
例如,如果要向x添加y,然后检查x是否大于某个值,则可以执行
if(25<x+=y)
代替
x+=y;if(x>25)
或者,也许您想在修剪后找到字符串的长度:
strlen(s=trim(s))
而不是
s=trim(s);strlen(s)
a = (b=c)+1;
设置b
为c
,然后设置a
为b+1
。
a=1+b=c
。您可以将PHP和JavaScript添加到列表中。
=
运算符的优先级在左边比在右边更高,因此1+x=2
有效,并且计算结果为3
如果可能,使用And / Or合并多个/嵌套。
即:
if (a && (b || c)) {
}
代替:
if (a) {
if (b) {
//Do Stuff
} elseif (c) {
//Do same stuff
}
}
&
,`|)删除更多字符。
&
代替而不是&&
删除1个字符会弄乱运算符的优先级,并且您必须加上括号才能使其正常工作。