Kilka małych wskazówek do gry w golfa
Te wskazówki były trochę za małe, aby rozdzielić odpowiedzi, więc wykorzystam tę odpowiedź do bardzo małych wskazówek dotyczących kodowania, które znalazłem lub wymyśliłem i nie zostały jeszcze wspomniane w innych poradach:
Usuwanie ostatniego znaku ciągu:
// I used to do something like this:
s.substring(0,s.length()-1) // 27 bytes
// But this is shorter:
s.replaceAll(".$","") // 21 bytes
W niektórych przypadkach wiesz wcześniej, jaki jest ostatni znak, a także wiesz, że ta postać występuje tylko raz w ciągu. W takim przypadku możesz .split
zamiast tego użyć :
// As example: "100%" to "100"
s.split("%")[0] // 15 bytes
Skróty kodowania:
// 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
Wszystkie kodowania mają kanoniczną nazwę używaną w java.nio
interfejsie API, a także kanoniczną nazwę używaną w interfejsach API java.io
i java.lang
. Oto pełna lista wszystkich obsługiwanych kodowań w Javie. Dlatego zawsze używaj najkrótszego z dwóch; drugi jest zwykle krótszy (jak UTF-8
vs utf8
, Windows-1252
vs Cp1252
itp.), ale nie zawsze ( UTF-16BE
vs UnicodeBigUnmarked
).
Losowa wartość logiczna:
// 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
Liczby pierwsze:
Istnieje wiele różnych sposobów sprawdzania liczb pierwszych lub uzyskania wszystkich liczb pierwszych, ale odpowiedź @ SaraJ tutaj jest najkrótsza. Oto kopia-wklej jako odniesienie:
// 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*/;}}
UWAGA: Zwykle możesz połączyć go z innymi istniejącymi pętlami, w zależności od tego, jak chcesz go używać, więc nie będziesz potrzebować oddzielnej metody. Na przykład zaoszczędziło to wiele bajtów w tej odpowiedzi .
Obcinanie liczb całkowitych zamiast Math.floor / Math.ceil:
Jeśli używasz dodatnich podwójnych / zmiennoprzecinkowych i chcesz floor
ich, nie używaj, Math.floor
ale (int)
zamiast tego użyj -cast (ponieważ Java obcina się na liczbach całkowitych):
double d = 54.99;
int n=(int)Math.floor(d); // 25 bytes
int m=(int)d; // 13 bytes
// Outputs 54 for both
Tę samą sztuczkę można zastosować do ujemnych podwójnych / zmiennoprzecinkowych, które chcesz ceil
zamiast tego:
double d = -54.99;
int n=(int)Math.ceil(d); // 24 bytes
int m=(int)d; // 13 bytes
// Outputs -54 for both
Użyj &1
zamiast %2
pozbyć się nawiasu:
Ponieważ Operator Pierwszeństwo od &
jest niższa niż standardowych operatorów arytmetycznych, jak */+-
i %
można pozbyć się nawiasów w niektórych przypadkach.
// So instead of this:
(i+j)%2 // 7 bytes
// Use this:
i+j&1 // 5 bytes
Zauważ, że to naprawdę nie pomaga w kontrolach boolean, ponieważ wtedy nadal potrzebujesz nawiasów, są one tylko trochę przesunięte:
(i+j)%2<1 // 9 bytes
(i+j&1)<1 // 9 bytes
BigIntegers i tworzenie zmiennych dla statycznych wywołań metod:
Korzystając z BigIntegers, utwórz go tylko raz, abyś mógł go ponownie użyć. Jak wiadomo, BigInteger zawiera pola statyczne ZERO
, ONE
a TEN
. Więc kiedy używasz tylko tych trzech, nie potrzebujesz, import
ale możesz użyć java.Math.BigInteger
bezpośrednio.
// 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
UWAGA: Musisz użyć, =null
więc t
jest zainicjowany, aby użyć t.
.
Czasami możesz dodać wiele BigIntegerów, aby utworzyć kolejny, aby zapisać bajty. Powiedzmy, że chcesz mieć BigIntegers 1,10,12
z jakiegoś powodu:
// 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
Jak słusznie zaznaczono w komentarzach, sztuczka z BigInteger t=null;
wywołaniami metody statycznej może być również używana z innymi klasami.
Na przykład tę odpowiedź z 2011 r. Można pograć w golfa:
// 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()
zamiast toCharArray()
Kiedy chcesz zapętlić znaki ciągu, zwykle robisz to:
for(char c:s.toCharArray()) // 27 bytes
// or this:
for(String c:s.split("")) // 25 bytes
Pętlowanie znaków może być przydatne podczas ich drukowania, dołączania do ciągu znaków lub czegoś podobnego.
Jednak, jeśli używać tylko znaków dla niektórych obliczeń numerycznych Unicode można zastąpić char
z int
I można zastąpić toCharArray()
z getBytes()
:
for(int c:s.getBytes()) // 23 bytes
Lub jeszcze krócej w Javie 8+:
s.chars().forEach(c->...) // 22 bytes
W Javie 10+ zapętlanie znaku do wydruku można teraz wykonywać również w 22 bajtach:
for(var c:s.split("")) // 22 bytes
Losowy przedmiot z 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
Sprawdź, czy ciąg znaków zawiera spacje wiodące / końcowe
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
Dlaczego to działa, gdy !=
w Strings jest sprawdzanie referencji zamiast wartości w Javie? Ponieważ String#trim
zwróci „ Kopię tego ciągu z usuniętą początkową i końcową białą spacją lub tego ciągu, jeśli nie ma wiodącej ani końcowej białej spacji . ” Użyłem tego, po tym, jak ktoś mi to zasugerował, w tej mojej odpowiedzi .
Palindrom:
Aby sprawdzić, czy Ciąg znaków jest palindromem (pamiętając o parzystych i nieparzystych długościach Ciągów), jest to najkrótszy ( .contains
działa tutaj, ponieważ wiemy, że zarówno Ciąg, jak i jego odwrócona postać są równej długości):
String s=...;
s.contains(new StringBuffer(s).reverse()) // 41 bytes
.contains(...)
zamiast .equals(...+"")
dzięki komentarzowi @assylias tutaj .
Albo jest 0, albo oba są 0?
Myślę, że większość już wie to jedno: jeśli chcesz sprawdzić, czy albo a
czy b
jest zero, zamiast mnożyć zapisać bajtów:
a==0|b==0 // 9 bytes
a*b==0 // 6 bytes
A jeśli chcesz sprawdzić, czy oba a
i b
są zerowe, można użyć bitowym OR, lub dodać je razem, jeśli są zawsze pozytywne:
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)
Parzysty = 1, nieparzysty = -1; lub odwrotnie
// 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
Powodem, dla którego to dodałem, było po zobaczeniu k+(k%2<1?1:-1)
w tej odpowiedzi :
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
Czasy pętli w pełnym programie
Jeśli mamy wyzwanie, w którym pełny program jest obowiązkowy i musimy zapętlić określoną liczbę razy, możemy wykonać następujące czynności:
// 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
To samo dotyczy sytuacji, gdy musimy przyjąć ten zakres jako dane wejściowe:
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
Podziękowania dla @JackAmmo w tym komentarzu .
try-wreszcie zamiast try-catch (wyjątek e) podczas powrotu i kiedy go użyć
Jeśli nie możesz użyć, throws Exception
ale musisz catch
coś z tym zrobić przed powrotem, możesz finally
zamiast tego użyć :
try{...}catch(Exception e){return ...;} // 33 bytes
try{...}finally{return ...;} // 22 bytes
Jako przykład, kiedy użyć a try-catch
, mogę odnieść się do mojej odpowiedzi (uznanie dla pośredniego golfa należy do @KamilDrakari ). W tym wyzwaniu musimy zapętlić po przekątnej macierz NxM, więc musimy ustalić, czy liczba kolumn czy liczba wierszy jest najniższa jako nasze maksimum w pętli for (co jest dość drogie pod względem bajtów:) i<Math.min(a.length,a[0].length)
. Więc po prostu złapanie ArrayIndexOutOfBoundsException
użycia catch-finally
jest krótsze niż ta kontrola, a tym samym oszczędza bajty:
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
UWAGA: Działa to tylko z powodu return r;
w końcu. Sugerowano mi zmodyfikowanie pierwszej komórki, tak jak @KamilDrakari zrobił w swojej odpowiedzi w języku C #, aby zapisać bajty. Jednak w Javie oznacza to, że będę musiał zmienić go na m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}
(73 bajty), faktycznie zwiększając liczbę bajtów zamiast zmniejszać, gdybym mógł użyć finally
.
Math.pow (2, n)
Jeśli potrzebujesz potęgi 2, nieco mądrzejsze podejście jest znacznie krótsze:
(int)Math.pow(2,n) // 16 bytes
(1<<n) // 6 bytes
Łączenie bitowych i logicznych kontroli zamiast używania nawiasów
Myślę, że do tej pory jest to dobrze znane &
i |
może być używane zamiast &&
i ||
w sprawdzeniach logicznych Java (boolean). W niektórych przypadkach nadal chcesz używać &&
zamiast &
zapobiegać błędom, na przykład index >= 0 && array[index].doSomething
. Jeśli &&
zmieniono by na &
tutaj, nadal będzie oceniać część, w której używa indeksu w tablicy, powodując ArrayIndexOutOfBoundsException
, stąd użycie &&
w tym przypadku zamiast &
.
Jak dotąd podstawy &&
/ ||
vs &
/ |
w Javie.
Gdy chcesz to sprawdzić (A or B) and C
, najkrótsze mogą się wydawać operatory bitowe:
(A|B)&C // 7 bytes
Ponieważ jednak operatorzy bitowi mają pierwszeństwo operatorów przed sprawdzeniami logicznymi, możesz połączyć oba te elementy, aby zapisać bajt tutaj:
A|B&&C // 6 bytes
Użyj n+=...-n
zamiast(long)...
Kiedy masz zarówno wejście, jak i wyjście w lambda, na przykład podczas używania Math.pow
, możesz zapisać bajt, używając n+=...-n
zamiast (long)...
.
Na przykład:
n->(long)Math.pow(10,n) // 23 bytes
n->n+=Math.pow(10,n)-n // 22 bytes
Ten zapisany bajt w tej odpowiedzi kopalni , a nawet dwa bajty, łącząc -n-1
się +~n
w tej odpowiedzi kopalni .
package
można pominąć.