Несколько небольших советов по игре в гольф
Эти советы были слишком малы для отдельных ответов, поэтому я буду использовать этот ответ для очень маленьких советов по поиску кода, которые я нашел или придумал, и пока не упоминается в других советах:
Удаление последнего символа строки:
// I used to do something like this:
s.substring(0,s.length()-1) // 27 bytes
// But this is shorter:
s.replaceAll(".$","") // 21 bytes
В некоторых случаях вы заранее знаете, какой последний символ, и также знаете, что этот символ встречается в строке только один раз. В этом случае вы можете использовать .split
вместо:
// As example: "100%" to "100"
s.split("%")[0] // 15 bytes
Сочетания клавиш:
// When you want to get the UTF-8 bytes I used to do this:
s.getBytes("UTF-8"); // 20 bytes
// But you can also use "UTF8" for the same result:
s.getBytes("UTF8"); // 19 bytes
Все кодировки имеют каноническое имя, используемое в java.nio
API, а также каноническое имя , используемое в java.io
и java.lang
API. Вот полный список всех поддерживаемых кодировок в Java. Поэтому всегда используйте самый короткий из двух; вторая обычно короче (как UTF-8
против utf8
, Windows-1252
против Cp1252
и т. д.), но не всегда ( UTF-16BE
против UnicodeBigUnmarked
).
Случайный логический:
// You could do something like this:
new java.util.Random().nextBoolean() // 36 bytes
// But as mentioned before in @Geobits' answer, Math.random() doesn't require an import:
Math.random()<.5 // 16 bytes
Штрихи:
Есть много разных способов проверить простые числа или получить все простые, но ответ @ SaraJ здесь самый короткий. Вот копия-вставка в качестве ссылки:
// Check if n is a prime:
n->{int i=1;for(;n%++i%n>0;);return n==i;}
// Which can easily be modified to loop through primes:
v->{for(int n=2,i;;){for(i=1;n%++i%n>0;);if(n++==i)/*do something with prime `i` here*/;}}
ПРИМЕЧАНИЕ. Обычно вы можете объединить его с другими существующими циклами в зависимости от того, как вы хотите его использовать, поэтому вам не понадобится отдельный метод. Это сэкономило много байтов в этом ответе, например.
Целочисленное усечение вместо Math.floor / Math.ceil:
Если вы используете положительный double / float и хотите floor
их использовать, не используйте, Math.floor
а (int)
вместо этого используйте -cast (поскольку Java усекает целые числа):
double d = 54.99;
int n=(int)Math.floor(d); // 25 bytes
int m=(int)d; // 13 bytes
// Outputs 54 for both
Тот же трюк может быть применен к отрицательным двойным / плавающим числам, которые вы хотитеceil
вместо этого:
double d = -54.99;
int n=(int)Math.ceil(d); // 24 bytes
int m=(int)d; // 13 bytes
// Outputs -54 for both
Используйте &1
вместо того, %2
чтобы избавиться от скобок:
Поскольку оператор Внеочередной из &
ниже арифметических операторов по умолчанию , как*/+-
и %
вы можете избавиться от скобок в некоторых случаях.
// So instead of this:
(i+j)%2 // 7 bytes
// Use this:
i+j&1 // 5 bytes
Обратите внимание, что это не очень помогает в булевых проверках, потому что тогда вам все еще понадобятся скобки, они просто немного сдвинуты:
(i+j)%2<1 // 9 bytes
(i+j&1)<1 // 9 bytes
BigIntegers и создание переменных для вызовов статических методов:
При использовании BigIntegers, создайте его только один раз, который затем сможете использовать повторно. Как вы знаете, BigInteger содержит статические поля для ZERO
, ONE
и TEN
. Поэтому, когда вы используете только эти три, вам не нужно, import
но можете использовать java.Math.BigInteger
напрямую.
// So instead of this:
import java.math.BigInteger.*;
BigInteger a=BigInteger.ONE,b=BigInteger.ZERO; // 76 bytes
// or this:
java.math.BigInteger a=java.math.BigInteger.ONE,b=a.ZERO; // 57 bytes
// Use this:
java.math.BigInteger t=null,a=t.ONE,b=t.ZERO; // 45 bytes
ПРИМЕЧАНИЕ: вы должны использовать =null
такt
инициализировано для использования t.
.
Иногда вы можете добавить несколько BigIntegers, чтобы создать другой для сохранения байтов. Допустим, вы хотите иметь BigIntegers 1,10,12
по какой-то причине:
// So instead of this:
BigInteger t=null,a=t.ONE,b=t.TEN,c=new BigInteger(12); // 55 bytes
// Use this:
BigInteger t=null,a=t.ONE,b=t.TEN,c=b.add(a).add(a); // 52 bytes
Как правильно указано в комментариях, трюк с BigInteger t=null;
вызовами статических методов также можно использовать с другими классами.
Например, этот ответ с 2011 года может быть гольфом:
// 173 bytes:
import java.util.*;class g{public static void main(String[]p){String[]a=p[0].split(""),b=p[1].split("");Arrays.sort(a);Arrays.sort(b);System.out.print(Arrays.equals(a,b));}}
// 163 bytes
class g{public static void main(String[]p){java.util.Arrays x=null;String[]a=p[0].split(""),b=p[1].split("");x.sort(a);x.sort(b);System.out.print(x.equals(a,b));}}
getBytes()
вместо toCharArray()
Когда вы хотите зациклить символы строки, вы обычно делаете это:
for(char c:s.toCharArray()) // 27 bytes
// or this:
for(String c:s.split("")) // 25 bytes
Циклы по символам могут быть полезны при их печати, или добавлении их в строку, или что-то подобное.
Однако, если вы используете только символы для некоторых расчетов юникода-номер, вы можете заменить char
с int
, и вы можете заменить toCharArray()
с getBytes()
:
for(int c:s.getBytes()) // 23 bytes
Или даже короче в Java 8+:
s.chars().forEach(c->...) // 22 bytes
В Java 10+ зацикливание на символе для печати теперь также может выполняться в 22 байта:
for(var c:s.split("")) // 22 bytes
Случайный предмет из List
:
List l=...;
// When we have an `import java.util.*;` in our code, shuffling is shortest:
return l.get(new Random().nextInt(l.size())); // 45 bytes
return l.get((int)(Math.random()*l.size())); // 44 bytes
Collections.shuffle(l);return l.get(0); // 39 bytes
// When we don't have an `import java.util.*` in our code, `Math.random` is shortest:
return l.get(new java.util.Random().nextInt(l.size())); // 55 bytes
return l.get((int)(Math.random()*l.size())); // 44 bytes
java.util.Collections.shuffle(l);return l.get(0); // 49 bytes
Проверьте, содержит ли строка начальные / конечные пробелы
String s=...;
// I used to use a regex like this:
s.matches(" .*|.* ") // 20 bytes
// But this is shorter:
!s.trim().equals(s) // 19 bytes
// And this is even shorter due to a nice feature of String#trim:
s!=s.trim() // 11 bytes
Почему это работает, когда !=
в Strings нужно проверять ссылку, а не значение в Java? Потому String#trim
что вернет « Копию этой строки с удаленными начальным и конечным пробелами, или эту строку, если у нее нет начальных или конечных пробелов» . Я использовал это после того, как кто-то предложил мне это, в этом моем ответе .
Палиндром:
Чтобы проверить, является ли String палиндромом (имея в виду как четные, так и нечетные длины строк), это самое короткое ( .contains
работает здесь, потому что мы знаем, что и сама строка, и ее обращенная форма имеют одинаковую длину):
String s=...;
s.contains(new StringBuffer(s).reverse()) // 41 bytes
.contains(...)
а не .equals(...+"")
благодаря комментарию @assylias здесь .
Либо 0, либо оба 0?
Я думаю, что большинство уже знают это: если вы хотите проверить, равен a
или b
равен нулю, умножьте вместо этого, чтобы сохранить байты:
a==0|b==0 // 9 bytes
a*b==0 // 6 bytes
И если вы хотите проверить , равны ли оба a
и b
равны нулю, вы можете использовать побитовое ИЛИ или сложить их вместе, если они всегда положительны:
a==0&b==0 // 9 bytes
(a|b)==0 // 8 bytes (if either `a`, `b` or both can be negative)
a+b<1 // 5 bytes (this only works if neither `a` nor `b` can be negative)
Четный = 1, нечетный = -1; или наоборот
// even = 1; odd = -1:
n%2<1?1:-1 // 10 bytes
1-n%2*2 // 7 bytes
// even = -1; odd = 1:
n%2<1?-1:1 // 10 bytes
n%2*2-1 // 7 bytes
Поэтому я добавить это после того, как видит k+(k%2<1?1:-1)
в этом ответе :
k+(k%2<1?1:-1) // 14 bytes
// This would already have been shorter:
k%2<1?k+1:k-1 // 13 bytes
// But it can also be:
k%2*-2-~k // 9 bytes
петля n
Время в полной программе
Если у нас есть проблема, когда полная программа обязательна, и нам нужно выполнить определенное количество циклов, мы можем сделать следующее:
// instead of:
interface M{static void main(String[]a){for(int n=50;n-->0;)/*do something*/}} // 78 bytes
// we could do:
interface M{static void main(String[]a){for(M m:new M[50])/*do something*/}} // 76 bytes
То же самое относится, когда мы должны принять этот диапазон в качестве входных данных:
interface M{static void main(String[]a){for(int n=new Byte(a[0]);n-->0;)/*do something*/}} // 90 bytes
interface M{static void main(String[]a){for(M m:new M[new Byte(a[0])])/*do something*/}} // 88 bytes
Кредит @JackAmmo в этом комментарии .
try-finally вместо try-catch (исключение e) при возврате и когда его использовать
Если вы не можете использовать a, throws Exception
но должны catch
и что-то сделать с ним до возвращения, вы можете использовать finally
вместо этого:
try{...}catch(Exception e){return ...;} // 33 bytes
try{...}finally{return ...;} // 22 bytes
Что касается примера того, когда использовать a try-catch
, я могу сослаться на этот мой ответ (кредит на косвенный гольф идет в @KamilDrakari ). В этой задаче мы должны по диагонали зациклить матрицу NxM, поэтому мы должны определить, является ли количество столбцов или количество строк наименьшим, как наш максимум в цикле for (что довольно дорого с точки зрения байтов:) i<Math.min(a.length,a[0].length)
. Таким образом, простое отслеживание ArrayIndexOutOfBoundsException
использования catch-finally
короче, чем эта проверка, и, таким образом, сохраняет байты:
int[] a = ...;
int r=0,i=0;for(;i<Math.min(a.length,a[0].length);)r=...i++...;return r; // 66 bytes
int r=0,i=0;try{for(;;)r=...i++...;}finally{return r;} // 48 bytes
ПРИМЕЧАНИЕ. Это сработало только из- return r;
за окончательного варианта. Мне предложили изменить первую ячейку, как @KamilDrakari в своем ответе на C #, чтобы сохранить байты. Однако в Java это означает, что мне придется изменить его на m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}
(73 байта), фактически увеличивая количество байтов вместо уменьшения, если бы я мог использоватьfinally
.
Math.pow (2, п)
Когда вы хотите степень 2, побитовый подход намного короче:
(int)Math.pow(2,n) // 16 bytes
(1<<n) // 6 bytes
Объединение битовых и логических проверок вместо использования скобок
Я думаю, что к настоящему времени известно, что &
и |
может использоваться вместо &&
и ||
в логических проверках Java (логических). В некоторых случаях вы все равно хотите использовать &&
вместо того, &
чтобы предотвратить ошибки, как, например index >= 0 && array[index].doSomething
. Если значение &&
будет изменено на &
здесь, он все равно будет оценивать ту часть, где он использует индекс в массиве, вызывая ArrayIndexOutOfBoundsException
, следовательно, использование &&
в этом случае вместо&
.
Пока что основы &&
/ ||
vs &
/|
в Java.
Когда вы хотите проверить (A or B) and C
, может показаться, что самые короткие используют побитовые операторы:
(A|B)&C // 7 bytes
Однако, поскольку побитовые операторы имеют приоритет операторов над логическими проверками, вы можете объединить оба, чтобы сохранить байт здесь:
A|B&&C // 6 bytes
Используйте n+=...-n
вместо(long)...
Если у вас есть длинная длина и в лямбда-выходе, например, при использовании Math.pow
, вы можете сохранить байт, используя n+=...-n
вместо (long)...
.
Например:
n->(long)Math.pow(10,n) // 23 bytes
n->n+=Math.pow(10,n)-n // 22 bytes
Это спасло байты в этом ответе шахты , и даже два байта, комбинируя -n-1
в +~n
в этом ответе шахты .
package
можно пропустить