Несколько небольших советов по игре в гольф
Эти советы были слишком малы для отдельных ответов, поэтому я буду использовать этот ответ для очень маленьких советов по поиску кода, которые я нашел или придумал, и пока не упоминается в других советах:
Удаление последнего символа строки:
// 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.langAPI. Вот полный список всех поддерживаемых кодировок в 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можно пропустить