Một số mẹo chơi gôn nhỏ
Các mẹo này hơi nhỏ đối với các câu trả lời riêng biệt, vì vậy tôi sẽ sử dụng câu trả lời này cho các mẹo mã hóa rất nhỏ mà tôi đã tìm thấy hoặc đưa ra và chưa được đề cập trong các mẹo khác:
Xóa ký tự cuối cùng của Chuỗi:
// I used to do something like this:
s.substring(0,s.length()-1) // 27 bytes
// But this is shorter:
s.replaceAll(".$","") // 21 bytes
Trong một số trường hợp, bạn biết ký tự cuối cùng là gì trước đó và bạn cũng biết ký tự này chỉ xảy ra một lần trong Chuỗi. Trong trường hợp đó, bạn có thể sử dụng .split
thay thế:
// As example: "100%" to "100"
s.split("%")[0] // 15 bytes
Phím tắt mã hóa:
// 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
Tất cả các mã hóa đều có tên chính tắc được sử dụng trong java.nio
API, cũng như tên chính tắc được sử dụng trong java.io
và java.lang
API. Dưới đây là danh sách đầy đủ tất cả các mã hóa được hỗ trợ trong Java. Vì vậy, luôn luôn sử dụng ngắn nhất trong hai; cái thứ hai thường ngắn hơn (như UTF-8
vs utf8
, Windows-1252
vs Cp1252
, v.v.), nhưng không phải lúc nào cũng ( UTF-16BE
vs UnicodeBigUnmarked
).
Boolean ngẫu nhiên:
// 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
Số nguyên tố:
Có rất nhiều cách khác nhau để kiểm tra các số nguyên tố hoặc nhận tất cả các số nguyên tố, nhưng câu trả lời của @ SaraJ ở đây là ngắn nhất. Đây là một bản sao-dán làm tài liệu tham khảo:
// 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*/;}}
LƯU Ý: Thông thường bạn có thể hợp nhất nó với các vòng lặp hiện có khác tùy thuộc vào cách bạn muốn sử dụng nó, vì vậy bạn sẽ không cần một phương pháp riêng. Điều này đã lưu rất nhiều byte trong câu trả lời này chẳng hạn.
Cắt bớt số nguyên thay vì Math.floor / Math.ceil:
Nếu bạn đang sử dụng nhân đôi / số dương và bạn muốn floor
sử dụng chúng, đừng sử dụng Math.floor
mà (int)
thay vào đó hãy sử dụng một -cast (vì Java cắt ngắn trên các số nguyên):
double d = 54.99;
int n=(int)Math.floor(d); // 25 bytes
int m=(int)d; // 13 bytes
// Outputs 54 for both
Thay vào đó, mẹo tương tự có thể được áp dụng cho các lần tăng / giảm âm mà bạn muốn ceil
:
double d = -54.99;
int n=(int)Math.ceil(d); // 24 bytes
int m=(int)d; // 13 bytes
// Outputs -54 for both
Sử dụng &1
thay vì %2
để thoát khỏi dấu ngoặc đơn:
Bởi vì Phương thức ưu tiên của &
là thấp hơn so với các nhà khai thác số học mặc định như */+-
và %
, bạn có thể thoát khỏi dấu ngoặc đơn trong một số trường hợp.
// So instead of this:
(i+j)%2 // 7 bytes
// Use this:
i+j&1 // 5 bytes
Lưu ý rằng điều này không thực sự hữu ích trong kiểm tra boolean, bởi vì sau đó bạn vẫn cần dấu ngoặc đơn, chúng chỉ được di chuyển một chút:
(i+j)%2<1 // 9 bytes
(i+j&1)<1 // 9 bytes
BigIntegers và tạo các biến cho các cuộc gọi phương thức tĩnh:
Khi sử dụng BigIntegers, chỉ tạo một lần mà sau đó bạn có thể sử dụng lại. Như bạn đã biết, BigInteger chứa các lĩnh vực tĩnh cho ZERO
, ONE
và TEN
. Vì vậy, khi bạn chỉ sử dụng ba thứ đó, bạn không cần import
nhưng có thể sử dụng java.Math.BigInteger
trực tiếp.
// 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
LƯU Ý: Bạn phải sử dụng =null
để t
được khởi tạo để sử dụng t.
.
Đôi khi bạn có thể thêm nhiều BigIntegers để tạo một cái khác để lưu byte. Vì vậy, hãy nói rằng bạn muốn có BigIntegers 1,10,12
vì một số lý do:
// 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
Như đã chỉ ra một cách chính xác trong các bình luận, mẹo với BigInteger t=null;
các cuộc gọi phương thức tĩnh cũng có thể được sử dụng với các lớp khác.
Ví dụ, câu trả lời từ năm 2011 này có thể được đánh gôn:
// 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()
thay vì toCharArray()
Khi bạn muốn lặp qua các ký tự của Chuỗi, bạn sẽ thường làm điều này:
for(char c:s.toCharArray()) // 27 bytes
// or this:
for(String c:s.split("")) // 25 bytes
Vòng lặp trên các ký tự có thể hữu ích khi in chúng hoặc nối chúng vào Chuỗi hoặc một cái gì đó tương tự.
Tuy nhiên, nếu bạn chỉ sử dụng ký tự cho một số phép tính số unicode, bạn có thể thay thế char
bằng int
, VÀ bạn có thể thay thế toCharArray()
bằng getBytes()
:
for(int c:s.getBytes()) // 23 bytes
Hoặc thậm chí ngắn hơn trong Java 8+:
s.chars().forEach(c->...) // 22 bytes
Trong Java 10+, việc lặp lại ký tự cần in giờ cũng có thể được thực hiện bằng 22 byte:
for(var c:s.split("")) // 22 bytes
Mục ngẫu nhiên từ một 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
Kiểm tra xem Chuỗi có chứa khoảng trắng ở đầu / cuối không
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
Tại sao điều này hoạt động, khi !=
trên Chuỗi là để kiểm tra tham chiếu thay vì giá trị trong Java? Bởi vì String#trim
sẽ trả về " Một bản sao của chuỗi này với khoảng trắng ở đầu và cuối bị xóa hoặc chuỗi này nếu nó không có khoảng trắng ở đầu hoặc cuối . " Tôi đã sử dụng nó, sau khi ai đó gợi ý cho tôi, trong câu trả lời này của tôi .
Palindrom:
Để kiểm tra xem Chuỗi có phải là một palindrom hay không (lưu ý cả độ dài chẵn và lẻ của Chuỗi), đây là đoạn ngắn nhất ( .contains
hoạt động ở đây vì chúng ta biết cả chính Chuỗi và dạng đảo ngược của nó có độ dài bằng nhau):
String s=...;
s.contains(new StringBuffer(s).reverse()) // 41 bytes
.contains(...)
thay vì .equals(...+"")
cảm ơn bình luận của @assylias ở đây .
Hoặc là 0, hoặc cả hai đều là 0?
Tôi nghĩ rằng hầu hết đã biết điều này: nếu bạn muốn kiểm tra xem một trong hai a
hoặc b
bằng 0, thay vào đó hãy nhân lên để lưu byte:
a==0|b==0 // 9 bytes
a*b==0 // 6 bytes
Và nếu bạn muốn kiểm tra xem cả hai a
và b
bằng không, bạn có thể sử dụng bit-OR hoặc thêm chúng lại với nhau nếu chúng luôn dương:
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)
Chẵn = 1, lẻ = -1; hoặc ngược lại
// 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
Lý do tôi thêm điều này là sau khi thấy k+(k%2<1?1:-1)
trong câu trả lời này :
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
Thời gian lặp trong chương trình đầy đủ
Nếu chúng tôi có một thách thức trong đó một chương trình đầy đủ là bắt buộc và chúng tôi cần lặp một số lần cụ thể, chúng tôi có thể làm như sau:
// 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
Điều tương tự cũng áp dụng khi chúng ta phải lấy phạm vi này làm đầu vào:
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
Tín dụng cho @JackAmmo trong bình luận này .
thử-cuối cùng thay vì thử bắt (Ngoại lệ e) khi quay lại và khi nào sử dụng nó
Nếu bạn không thể sử dụng throws Exception
nhưng phải catch
và làm một cái gì đó với nó trước khi quay lại, bạn có thể sử dụng finally
thay thế:
try{...}catch(Exception e){return ...;} // 33 bytes
try{...}finally{return ...;} // 22 bytes
Ví dụ về thời điểm sử dụng a try-catch
, tôi có thể tham khảo câu trả lời này của tôi (tín dụng cho môn đánh gôn gián tiếp được gửi tới @KamilDrakari ). Trong thử thách này, chúng tôi phải lặp theo đường chéo trên ma trận NxM, vì vậy chúng tôi phải xác định xem số lượng cột hoặc số lượng hàng có thấp nhất là mức tối đa của chúng tôi trong vòng lặp for (khá tốn kém về byte i<Math.min(a.length,a[0].length)
). Vì vậy, chỉ cần nắm bắt việc ArrayIndexOutOfBoundsException
sử dụng catch-finally
ngắn hơn kiểm tra này và do đó tiết kiệm byte:
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
LƯU Ý: Điều này chỉ hoạt động vì return r;
cuối cùng. Tôi đã được đề nghị sửa đổi ô đầu tiên, như @KamilDrakari đã làm trong câu trả lời C # của mình để lưu byte. Tuy nhiên, trong Java, điều này có nghĩa là tôi sẽ phải thay đổi nó thành m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}
(73 byte), thực sự tăng số byte thay vì giảm nếu tôi có thể sử dụng finally
.
Math.pow (2, n)
Khi bạn muốn có sức mạnh bằng 2, cách tiếp cận khôn ngoan sẽ ngắn hơn nhiều:
(int)Math.pow(2,n) // 16 bytes
(1<<n) // 6 bytes
Kết hợp kiểm tra bit-khôn ngoan và logic thay vì sử dụng dấu ngoặc đơn
Tôi nghĩ rằng bây giờ nó đã được biết đến &
và |
có thể được sử dụng thay vì &&
và ||
trong kiểm tra logic (boolean) của Java. Trong một số trường hợp, bạn vẫn muốn sử dụng &&
thay vì &
để tránh lỗi, như thế index >= 0 && array[index].doSomething
. Nếu &&
thay đổi &
ở đây, nó vẫn sẽ đánh giá phần mà nó sử dụng chỉ mục trong mảng, gây ra một ArrayIndexOutOfBoundsException
, do đó việc sử dụng &&
trong trường hợp này thay vì &
.
Cho đến nay những điều cơ bản của &&
/ ||
vs &
/ |
trong Java.
Khi bạn muốn kiểm tra (A or B) and C
, dường như ngắn nhất có thể sử dụng các toán tử bit khôn ngoan như thế này:
(A|B)&C // 7 bytes
Tuy nhiên, vì các toán tử bit-bit có quyền ưu tiên toán tử so với các kiểm tra logic, bạn có thể kết hợp cả hai để lưu một byte ở đây:
A|B&&C // 6 bytes
Sử dụng n+=...-n
thay vì(long)...
Khi bạn có cả đầu vào và đầu ra trong lambda, ví dụ như khi sử dụng Math.pow
, bạn có thể lưu một byte bằng cách sử dụng n+=...-n
thay vì (long)...
.
Ví dụ:
n->(long)Math.pow(10,n) // 23 bytes
n->n+=Math.pow(10,n)-n // 22 bytes
Đây lưu một byte trong câu trả lời này của tôi , và thậm chí cả hai byte bằng cách kết hợp -n-1
để +~n
trong câu trả lời này của tôi .
package
có thể bỏ qua