Algumas pequenas dicas sobre golfe com códigos
Essas dicas eram um pouco pequenas para respostas separadas, portanto, usarei essa resposta para dicas muito pequenas de codegolf que encontrei ou que surgiram e ainda não foram mencionadas nas outras dicas:
Removendo o último caractere de uma String:
// I used to do something like this:
s.substring(0,s.length()-1) // 27 bytes
// But this is shorter:
s.replaceAll(".$","") // 21 bytes
Em alguns casos, você sabe qual é o último caractere de antemão e também sabe que esse caractere ocorre apenas uma vez na String. Nesse caso, você pode usar .split
:
// As example: "100%" to "100"
s.split("%")[0] // 15 bytes
Atalhos de codificação:
// 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
Todas as codificações têm um nome canônico usado na java.nio
API, bem como um nome canônico usado nas APIs java.io
e java.lang
. Aqui está uma lista completa de todas as codificações suportadas em Java. Portanto, sempre use o menor dos dois; o segundo é geralmente mais curto (como UTF-8
vs utf8
, Windows-1252
vs Cp1252
, etc.), mas nem sempre ( UTF-16BE
vs UnicodeBigUnmarked
).
Booleano aleatório:
// 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
Primes:
Existem várias maneiras diferentes de verificar primos ou obter todos os primos, mas a resposta de @ SaraJ aqui é a mais curta. Aqui está um copiar e colar como referência:
// 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*/;}}
NOTA: Geralmente, você pode mesclá-lo com outros loops existentes, dependendo de como deseja usá-lo, para não precisar de um método separado. Isso economizou muitos bytes nesta resposta, por exemplo.
Truncamento inteiro em vez de Math.floor / Math.ceil:
Se você estiver usando duplos / flutuadores positivos e desejar floor
, não use, Math.floor
mas use um (int)
-cast (pois o Java trunca em números inteiros):
double d = 54.99;
int n=(int)Math.floor(d); // 25 bytes
int m=(int)d; // 13 bytes
// Outputs 54 for both
O mesmo truque pode ser aplicado aos duplos / flutuadores negativos que você deseja ceil
:
double d = -54.99;
int n=(int)Math.ceil(d); // 24 bytes
int m=(int)d; // 13 bytes
// Outputs -54 for both
Use em &1
vez de %2
se livrar dos parênteses:
Como a Precedência do operador de &
é menor que os operadores aritméticos padrão como */+-
e %
, em alguns casos, você pode se livrar do parêntese.
// So instead of this:
(i+j)%2 // 7 bytes
// Use this:
i+j&1 // 5 bytes
Observe que isso realmente não ajuda nas verificações booleanas, porque você ainda precisa de parênteses, elas são apenas movidas um pouco:
(i+j)%2<1 // 9 bytes
(i+j&1)<1 // 9 bytes
BigIntegers e criando variáveis para chamadas de método estático:
Ao usar o BigIntegers, crie-o apenas uma vez e depois reutilize-o. Como você deve saber, o BigInteger contém campos estáticos para ZERO
, ONE
e TEN
. Portanto, quando você usa apenas esses três, não precisa de um, import
mas pode usá-lo java.Math.BigInteger
diretamente.
// 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
OBSERVAÇÃO: você deve usar =null
para que t
seja inicializado para poder usar t.
.
Às vezes, você pode adicionar vários BigIntegers para criar outro para salvar bytes. Então, digamos que você queira ter os BigIntegers 1,10,12
por algum motivo:
// 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
Como corretamente apontado nos comentários, o truque com BigInteger t=null;
as chamadas de método estático também pode ser usado com outras classes.
Por exemplo, esta resposta de 2011 pode ser jogada no golfe:
// 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()
ao invés de toCharArray()
Quando você deseja fazer um loop sobre os caracteres de uma String, geralmente você faz isso:
for(char c:s.toCharArray()) // 27 bytes
// or this:
for(String c:s.split("")) // 25 bytes
Fazer um loop sobre os caracteres pode ser útil ao imprimi-los ou anexá-los a uma String ou algo semelhante.
No entanto, se você usar apenas os caracteres para alguns cálculos de número unicode, poderá substituir char
por int
e AND toCharArray()
por getBytes()
:
for(int c:s.getBytes()) // 23 bytes
Ou ainda mais curto no Java 8+:
s.chars().forEach(c->...) // 22 bytes
No Java 10+, o loop sobre o caractere a ser impresso também pode ser feito em 22 bytes:
for(var c:s.split("")) // 22 bytes
Item aleatório de a 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
Verifique se uma String contém espaços iniciais / finais
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
Por que isso funciona, quando !=
em Strings é procurar referência em vez de valor em Java? Porque String#trim
retornará " Uma cópia dessa sequência com o espaço em branco à esquerda e à direita removido, ou essa sequência se não tiver espaço em branco à esquerda ou à direita . " Eu usei isso, depois que alguém me sugeriu isso, nesta resposta minha .
Palíndromo:
Para verificar se uma String é um palíndromo (tendo em mente os comprimentos pares e ímpares de Strings), este é o mais curto ( .contains
funciona aqui porque sabemos que a própria String e sua forma invertida têm o mesmo comprimento):
String s=...;
s.contains(new StringBuffer(s).reverse()) // 41 bytes
.contains(...)
em vez de .equals(...+"")
agradecer ao comentário de @assylias aqui .
Ou é 0 ou ambos são 0?
Eu acho que a maioria já conhece este: se você quiser verificar se é a
ou b
é zero, multiplique para salvar bytes:
a==0|b==0 // 9 bytes
a*b==0 // 6 bytes
E se você quiser verificar se ambos a
e b
são zero, você poderia usar um bit a bit-OR, ou adicioná-los juntos se eles são sempre positivos:
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)
Par = 1, ímpar = -1; ou vice-versa
// 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
A razão de eu adicionar este foi depois de ver k+(k%2<1?1:-1)
nos esta resposta :
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
Tempos de loop no programa completo
Se tivermos um desafio em que um programa completo é obrigatório e precisamos repetir uma quantidade específica de vezes, podemos fazer o seguinte:
// 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
O mesmo se aplica quando temos que usar esse intervalo como entrada:
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
Os créditos a @JackAmmo neste comentário .
try-finalmente em vez de try-catch (exceção e) ao retornar e quando usá-lo
Se você não pode usar um, throws Exception
mas precisa catch
fazer algo antes de retornar, pode usar finally
:
try{...}catch(Exception e){return ...;} // 33 bytes
try{...}finally{return ...;} // 22 bytes
Como exemplo de quando usar a try-catch
, posso me referir a esta resposta minha (o crédito para o golfe indireto vai para @KamilDrakari ). Nesse desafio, temos que fazer um loop diagonal sobre uma matriz NxM, portanto, precisamos determinar se a quantidade de colunas ou a quantidade de linhas é a mais baixa que a máxima no loop for (o que é bastante caro em termos de bytes :) i<Math.min(a.length,a[0].length)
. Portanto, simplesmente capturar o ArrayIndexOutOfBoundsException
uso catch-finally
é mais curto que essa verificação e, assim, salva bytes:
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
NOTA: Isso só funcionou por causa do return r;
no finalmente. Fui sugerido para modificar a primeira célula, como @KamilDrakari fez em sua resposta em C # para salvar bytes. No entanto, em Java, isso significa que terei que alterá-lo para m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}
(73 bytes), na verdade aumentando a contagem de bytes em vez de diminuir se eu pudesse usá-lo finally
.
Math.pow (2, n)
Quando você quer um poder de 2, uma abordagem pouco inteligente é muito mais curta:
(int)Math.pow(2,n) // 16 bytes
(1<<n) // 6 bytes
Combinando verificações bit a bit e lógicas em vez de usar parênteses
Eu acho que agora é bem conhecido &
e |
pode ser usado em vez de &&
e ||
nas verificações lógicas Java (booleanas). Em alguns casos, você ainda gostaria de usar em &&
vez de &
evitar erros, como index >= 0 && array[index].doSomething
. Se o &&
for alterado para &
aqui, ele ainda avaliará a parte em que usa o índice na matriz, causando um ArrayIndexOutOfBoundsException
, portanto, o uso de &&
neste caso, em vez de &
.
Até agora, o básico de &&
/ ||
vs &
/ |
em Java.
Quando você deseja verificar (A or B) and C
, o menor pode parecer usar os operadores bit a bit como este:
(A|B)&C // 7 bytes
No entanto, como os operadores bit a bit têm precedência de operador sobre as verificações lógicas, você pode combinar os dois para salvar um byte aqui:
A|B&&C // 6 bytes
Use em n+=...-n
vez de(long)...
Quando você tem um tempo entre in e output em um lambda, por exemplo, ao usar Math.pow
, é possível salvar um byte usando em n+=...-n
vez de (long)...
.
Por exemplo:
n->(long)Math.pow(10,n) // 23 bytes
n->n+=Math.pow(10,n)-n // 22 bytes
Isso salvou um byte em esta resposta da mina , e até dois bytes, combinando -n-1
a +~n
em esta resposta da mina .
package
pode ser pulado.