Java 7+, n = 50 trong ~ 30 giây trên TIO
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Random;
class Main{
public static void main(String[] a){
int n=50;
Random randomGenerator = new Random();
int i = n+1;
int squaredN = n*n;
int[]randomIntegers = new int[i];
randomIntegers[n] = squaredN;
while(true){
for(i=n; i-->1; ){
randomIntegers[i] = randomGenerator.nextInt(squaredN);
}
Set<Integer> result = new HashSet<>();
Arrays.sort(randomIntegers);
for(i=n; i-->0; ){
result.add(randomIntegers[i+1] - randomIntegers[i]);
}
if(!result.contains(0) && result.size()==n){
System.out.println(result);
return;
}
}
}
}
Hiện tại, phiên bản trả lời của tôi cho phiên bản golf-code của thử thách này , chỉ với một thay đổi nhỏ: java.util.Random#nextInt(limit)
được sử dụng thay (int)(Math.random()*limit)
cho số nguyên trong phạm vi [0, n)
, vì nó nhanh gấp đôi .
Hãy thử trực tuyến.
Giải trình:
Cách tiếp cận được sử dụng:
Mã được chia thành hai phần:
- Tạo một danh sách
n
số lượng số nguyên ngẫu nhiên tính tổng n squared
.
- Sau đó, nó kiểm tra xem tất cả các giá trị là duy nhất và không có giá trị nào bằng 0 và nếu là falsey, nó sẽ thử lại bước 1, rửa và lặp lại cho đến khi chúng ta có kết quả.
Bước 1 được thực hiện với các bước phụ sau:
1) Tạo một mảng n-1
số lượng số nguyên ngẫu nhiên trong phạm vi [0, n squared)
. Và thêm 0
và n squared
vào danh sách này. Điều này được thực hiện trong O(n+1)
hiệu suất.
2) Sau đó, nó sẽ sắp xếp mảng với nội dung java.util.Arrays.sort(int[])
, Điều này được thực hiện trong O(n*log(n))
hiệu suất, như được nêu trong các tài liệu:
Sắp xếp mảng int được chỉ định theo thứ tự số tăng dần. Thuật toán sắp xếp là một quicksort được điều chỉnh, được chuyển thể từ "Kỹ thuật sắp xếp chức năng" của Jon L. Bentley và M. Douglas McIlroy, Thực hành phần mềm và kinh nghiệm, Vol. 23 (11) P. 1249-1265 (tháng 11 năm 1993). Thuật toán này cung cấp hiệu suất n * log (n) trên nhiều tập dữ liệu khiến cho các quicksort khác giảm xuống thành hiệu suất bậc hai.
3) Tính hiệu số giữa mỗi cặp. Danh sách kết quả khác biệt này sẽ chứa các n
số nguyên tính tổng n squared
. Điều này được thực hiện trong O(n)
hiệu suất.
Dưới đây là một ví dụ:
// n = 4, nSquared = 16
// n-1 amount of random integers in the range [0, nSquared):
[11, 2, 5]
// Add 0 and nSquared to it, and sort:
[0, 2, 5, 11, 16]
// Calculate differences:
[2, 3, 6, 5]
// The sum of these differences will always be equal to nSquared
sum([2, 3, 6, 5]) = 16
Vì vậy, ba bước trên là khá tốt cho hiệu suất, không giống như bước 2 và vòng lặp xung quanh toàn bộ, đó là một lực lượng vũ phu cơ bản. Bước 2 được chia theo các bước phụ sau:
1) Danh sách khác biệt đã được lưu trong a java.util.Set
. Nó sẽ kiểm tra xem kích thước của Bộ này có bằng không n
. Nếu có, nó có nghĩa là tất cả các giá trị ngẫu nhiên chúng tôi tạo ra là duy nhất.
2) Và nó cũng sẽ kiểm tra xem nó không chứa 0
trong Set, kể từ khi thách thức yêu cầu cho các giá trị ngẫu nhiên trong phạm vi [1, X]
, nơi X
là n squared
trừ đi khoản [1, ..., n-1]
, như đã nói bởi @Skidsdev trong các bình luận bên dưới.
Nếu một trong hai tùy chọn ở trên (không phải tất cả các giá trị là duy nhất hoặc có số 0), nó sẽ tạo ra một mảng mới và Đặt lại bằng cách đặt lại bước 1. Điều này tiếp tục cho đến khi chúng tôi có kết quả. Bởi vì điều này, thời gian có thể thay đổi khá nhiều. Tôi đã thấy nó hoàn thành trong 3 giây một lần trên TIO n=50
, nhưng cũng chỉ trong 55 giây một lần cho n=50
.
Chứng minh tính đồng nhất:
Tôi không hoàn toàn chắc chắn làm thế nào để chứng minh điều này là hoàn toàn trung thực. Các java.util.Random#nextInt
đồng đều chắc chắn, như được mô tả trong các tài liệu:
Trả về giả danh tiếp theo, int
giá trị được phân phối đồng đều từ chuỗi trình tạo số ngẫu nhiên này. Hợp đồng chung nextInt
là một int
giá trị được tạo ra và trả lại giả. Tất cả 2 32int
giá trị có thể được tạo ra với (xấp xỉ) xác suất bằng nhau.
Sự khác biệt giữa các giá trị ngẫu nhiên (được sắp xếp) này tất nhiên không đồng nhất, nhưng các bộ tổng thể là đồng nhất. Một lần nữa, tôi không chắc làm thế nào để chứng minh điều này một cách toán học, nhưng đây là một tập lệnh sẽ đặt 10,000
các tập hợp được tạo (cho n=10
) vào một Bản đồ với một bộ đếm , trong đó hầu hết các tập hợp là duy nhất; một số lặp lại hai lần; và sự xuất hiện lặp lại tối đa thường là trong phạm vi [4,8]
.
Hướng dẫn cài đặt:
Vì Java là một ngôn ngữ khá nổi tiếng với nhiều thông tin có sẵn về cách tạo và chạy mã Java, tôi sẽ nói ngắn gọn về điều này.
Tất cả các công cụ được sử dụng trong mã của tôi đều có sẵn trong Java 7 (thậm chí có thể đã có trong Java 5 hoặc 6, nhưng hãy sử dụng 7 chỉ trong trường hợp). Tôi khá chắc chắn rằng Java 7 đã được lưu trữ, vì vậy tôi khuyên bạn nên tải xuống Java 8 để chạy mã của mình.
Suy nghĩ về cải tiến:
Tôi muốn tìm một cải tiến cho việc kiểm tra các số không và kiểm tra tất cả các giá trị là duy nhất. Tôi có thể kiểm tra 0
trước, bằng cách đảm bảo giá trị ngẫu nhiên mà chúng ta thêm vào mảng chưa có trong đó, nhưng điều đó có nghĩa là một vài điều: mảng phải là một ArrayList
phương thức để chúng ta có thể sử dụng phương thức dựng sẵn .contains
; một vòng lặp while nên được thêm vào cho đến khi chúng tôi tìm thấy một giá trị ngẫu nhiên chưa có trong Danh sách. Vì việc kiểm tra số 0 hiện được thực hiện với .contains(0)
Bộ (chỉ được kiểm tra một lần), nên kiểm tra hiệu suất tại thời điểm đó tốt hơn, so với việc thêm vòng lặp .contains
vào Danh sách, sẽ được kiểm tra ít nhất n
nhiều lần , nhưng rất có thể nhiều hơn.
Đối với kiểm tra tính duy nhất, chúng tôi chỉ có n
số lượng số nguyên ngẫu nhiên tổng hợp n squared
sau bước 1 của chương trình, vì vậy chỉ sau đó chúng tôi mới có thể kiểm tra xem tất cả có phải là duy nhất hay không. Có thể giữ một Danh sách có thể sắp xếp thay vì mảng và kiểm tra sự khác biệt ở giữa, nhưng tôi thực sự nghi ngờ rằng nó sẽ cải thiện hiệu suất hơn là chỉ đưa chúng vào Set
và kiểm tra xem kích thước của Bộ đó có phải là n
một lần không.