Java 7+, n = 50 ใน ~ 30 วินาทีบน 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;
}
}
}
}
คำตอบของฉันที่ไม่ได้อัปโหลดสำหรับเวอร์ชันcode-golf ของความท้าทายนี้ในตอนนี้มีการเปลี่ยนแปลงเพียงเล็กน้อยเท่านั้น: java.util.Random#nextInt(limit)
ใช้แทน(int)(Math.random()*limit)
จำนวนเต็มในช่วง[0, n)
เนื่องจากมันเร็วกว่าสองเท่า
ลองออนไลน์
คำอธิบาย:
วิธีการที่ใช้:
รหัสจะแบ่งออกเป็นสองส่วน:
- สร้างรายการของจำนวนของจำนวนเต็มแบบสุ่มจำนวนเงินนั้นไป
n
n squared
- จากนั้นจะตรวจสอบว่าค่าทั้งหมดเป็นค่าเฉพาะและไม่มีค่าใดเป็นศูนย์และหากค่าใดเป็นเท็จจะลองขั้นตอนที่ 1 อีกครั้งล้างและทำซ้ำจนกว่าเราจะได้ผลลัพธ์
ขั้นตอนที่ 1 เสร็จสิ้นด้วยขั้นตอนย่อยต่อไปนี้:
1) สร้างอาร์เรย์ของจำนวนของจำนวนเต็มแบบสุ่มในช่วงn-1
[0, n squared)
และเพิ่ม0
และn squared
ลงในรายการนี้ นี่คือO(n+1)
การปฏิบัติ
2) จากนั้นมันจะเรียงลำดับอาร์เรย์ด้วยบิวjava.util.Arrays.sort(int[])
ด์อินซึ่งจะทำในO(n*log(n))
ประสิทธิภาพตามที่ระบุไว้ในเอกสาร:
เรียงลำดับอาร์เรย์ที่ระบุไว้ในลำดับตัวเลข อัลกอริธึมการเรียงลำดับนั้นเป็น quicksort ที่ปรับจูนดัดแปลงมาจาก Jon L. Bentley และ M. Douglas McIlroy ของ "ฟังก์ชั่นการจัดเรียงวิศวกรรม", การปฏิบัติซอฟต์แวร์และประสบการณ์ฉบับที่ 23 (11) หน้า 1249-1265 (พฤศจิกายน 2536) อัลกอริธึมนี้นำเสนอประสิทธิภาพของ n * log (n) ในชุดข้อมูลจำนวนมากที่ทำให้ Quicksorts อื่น ๆ ลดประสิทธิภาพการทำงานเป็นกำลังสอง
3) คำนวณความแตกต่างระหว่างแต่ละคู่ รายการนี้เกิดจากความแตกต่างจะมีจำนวนเต็มได้ว่าจำนวนเงินที่จะn
n squared
นี่คือO(n)
การปฏิบัติ
นี่คือตัวอย่าง:
// 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
ดังนั้นสามขั้นตอนข้างต้นนี้ค่อนข้างดีสำหรับการแสดงซึ่งไม่เหมือนกับขั้นตอนที่ 2 และการวนซ้ำรอบ ๆ สิ่งทั้งหมดซึ่งเป็นแรงเดรัจฉานพื้นฐาน ขั้นตอนที่ 2 ถูกแบ่งในขั้นตอนย่อยเหล่านี้:
1) java.util.Set
รายการที่แตกต่างกันจะถูกบันทึกไว้แล้วใน n
มันจะตรวจสอบว่าขนาดของชุดนี้จะมีค่าเท่ากับ หากเป็นเช่นนั้นหมายความว่าค่าสุ่มทั้งหมดที่เราสร้างขึ้นนั้นไม่ซ้ำกัน
2) และก็ยังจะตรวจสอบว่ามันไม่มี0
ในชุดตั้งแต่ท้าทายขอค่าสุ่มในช่วง[1, X]
ที่X
เป็นn squared
ลบผลรวมของ[1, ..., n-1]
ดังกล่าวโดย@Skidsdevในความคิดเห็นดังต่อไปนี้
หากหนึ่งในสองตัวเลือกด้านบน (ไม่ใช่ค่าทั้งหมดจะไม่ซ้ำกันหรือมีค่าเป็นศูนย์) มันจะสร้างอาร์เรย์ใหม่และตั้งค่าอีกครั้งโดยการรีเซ็ตเป็นขั้นตอนที่ 1 ซึ่งจะดำเนินต่อไปจนกว่าเราจะได้ผลลัพธ์ ด้วยเหตุนี้เวลาจึงแตกต่างกันเล็กน้อย ผมเคยเห็นมันจบใน 3 วินาทีครั้งเดียวใน TIO สำหรับn=50
แต่ยังอยู่ใน 55 n=50
วินาทีครั้งสำหรับ
พิสูจน์ความสม่ำเสมอ:
ฉันไม่แน่ใจว่าจะพิสูจน์ได้อย่างไรว่านี่เป็นความซื่อสัตย์อย่างสมบูรณ์ java.util.Random#nextInt
เป็นชุดเพื่อตรวจสอบว่าเป็นที่อธิบายไว้ในเอกสาร:
ส่งคืน pseudorandom ถัดไปซึ่งมีการกระจายint
ค่าอย่างสม่ำเสมอจากลำดับตัวสร้างตัวเลขสุ่มนี้ สัญญาทั่วไปของnextInt
คือว่าหนึ่งint
ค่าจะถูกสร้างและส่งคืนแบบหลอกเทียม ค่าที่เป็นไปได้2 32int
ทั้งหมดนั้นสร้างขึ้นโดยมีความน่าจะเป็นเท่ากัน (โดยประมาณ)
ความแตกต่างระหว่างค่าสุ่มเหล่านี้ (เรียงลำดับ) ตัวเองแน่นอนว่าไม่เหมือนกัน แต่ชุดโดยรวมมีความเหมือนกัน อีกครั้งฉันไม่แน่ใจว่าจะพิสูจน์ทางคณิตศาสตร์ได้อย่างไร แต่นี่คือสคริปต์ที่จะนำ10,000
ชุดที่สร้างขึ้น (สำหรับn=10
) ลงในแผนที่ที่มีตัวนับซึ่งชุดส่วนใหญ่จะไม่ซ้ำกัน บางครั้งซ้ำสองครั้ง; [4,8]
และเกิดขึ้นซ้ำแล้วซ้ำอีกสูงสุดมักจะอยู่ในช่วง
คำแนะนำในการติดตั้ง:
เนื่องจาก Java เป็นภาษาที่รู้จักกันดีและมีข้อมูลมากมายเกี่ยวกับวิธีการสร้างและเรียกใช้รหัส Java ฉันจะเก็บย่อ
เครื่องมือทั้งหมดที่ใช้ในรหัสของฉันมีอยู่ใน Java 7 (อาจจะมีอยู่แล้วใน Java 5 หรือ 6 แต่ลองใช้ 7 ในกรณี) ฉันค่อนข้างมั่นใจว่า Java 7 นั้นถูกเก็บถาวรแล้วดังนั้นฉันขอแนะนำให้ดาวน์โหลด Java 8 เพื่อเรียกใช้รหัสของฉัน
ความคิดเกี่ยวกับการปรับปรุง:
ฉันต้องการค้นหาการปรับปรุงสำหรับการตรวจสอบสำหรับศูนย์และตรวจสอบค่าทั้งหมดจะไม่ซ้ำกัน ฉันสามารถตรวจสอบ0
ก่อนโดยตรวจสอบให้แน่ใจว่าค่าสุ่มที่เราเพิ่มไปยังอาร์เรย์ไม่ได้อยู่ในนั้น แต่มันหมายถึงสองสิ่ง: อาร์เรย์ควรเป็นArrayList
เพื่อให้เราสามารถใช้วิธีการ builtin .contains
; ควรเพิ่ม while-loop จนกว่าเราจะพบค่าสุ่มที่ยังไม่ได้อยู่ในรายการ เนื่องจากการตรวจสอบศูนย์เสร็จสิ้นด้วย.contains(0)
การตั้งค่า (ซึ่งถูกตรวจสอบเพียงครั้งเดียว) จึงเป็นการดีกว่าสำหรับการตรวจสอบที่จุดนั้นเมื่อเทียบกับการเพิ่มการวนซ้ำกับ.contains
ในรายการซึ่งจะตรวจสอบอย่างน้อยn
ครั้ง แต่มีแนวโน้มมากขึ้น
สำหรับการตรวจสอบความเป็นเอกลักษณ์เรามีเพียงn
จำนวนเต็มแบบสุ่มที่รวมไปถึงn squared
หลังขั้นตอนที่ 1 ของโปรแกรมดังนั้นจากนั้นเราสามารถตรวจสอบว่าทั้งหมดนั้นไม่ซ้ำกันหรือไม่ อาจเป็นไปได้ที่จะเก็บ Listable เรียงแทนที่จะเป็น Array และตรวจสอบความแตกต่างระหว่างกัน แต่ฉันสงสัยอย่างจริงจังว่ามันจะปรับปรุงประสิทธิภาพมากกว่าเพียงแค่ใส่ไว้ในSet
และตรวจสอบว่าขนาดของ Set นั้นเป็นn
หนึ่งครั้งหรือไม่