คำตอบที่ยอดเยี่ยมของ caf จะพิมพ์ตัวเลขแต่ละตัวที่ปรากฏ k ครั้งในอาร์เรย์ k-1 ครั้ง นั่นเป็นพฤติกรรมที่มีประโยชน์ แต่คำถามนั้นเรียกร้องให้พิมพ์ซ้ำแต่ละรายการเพียงครั้งเดียวและเขากล่าวถึงความเป็นไปได้ที่จะทำสิ่งนี้โดยไม่ต้อง จำกัด เวลาเชิงเส้น / ขอบเขตของพื้นที่คงที่ ซึ่งสามารถทำได้โดยแทนที่ลูปที่สองของเขาด้วยรหัสเทียมต่อไปนี้:
for (i = 0; i < N; ++i) {
if (A[i] != i && A[A[i]] == A[i]) {
print A[i];
A[A[i]] = i;
}
}
สิ่งนี้ใช้ประโยชน์จากคุณสมบัติที่หลังจากลูปแรกทำงานหากค่าใด ๆm
ปรากฏมากกว่าหนึ่งครั้งการปรากฏอย่างใดอย่างหนึ่งเหล่านั้นจะได้รับการรับรองว่าอยู่ในตำแหน่งที่ถูกต้องกล่าวคือA[m]
ปรากฏมากกว่าหนึ่งครั้งจากนั้นหนึ่งของสิ่งที่ปรากฏเหล่านั้นรับประกันได้ว่าจะอยู่ในตำแหน่งที่ถูกต้องคือหากเราระมัดระวังเราสามารถใช้ตำแหน่ง "บ้าน" นั้นเพื่อจัดเก็บข้อมูลว่ามีการพิมพ์ซ้ำหรือยัง
ในเวอร์ชันของ caf ขณะที่เราอ่านอาร์เรย์A[i] != i
โดยนัยว่าA[i]
เป็นข้อมูลที่ซ้ำกัน ในเวอร์ชันของฉันฉันใช้ค่าคงที่ที่แตกต่างกันเล็กน้อยนั่นA[i] != i && A[A[i]] == A[i]
หมายความว่าA[i]
ซ้ำกันที่เราไม่เคยเห็นมาก่อนว่าเราไม่ได้เห็นมาก่อน(หากคุณวางส่วน "ที่เราไม่เคยเห็นมาก่อน" ส่วนที่เหลือสามารถเห็นได้โดยนัยโดยความจริงของค่าคงที่ของคาเฟ่และการรับประกันว่ารายการที่ซ้ำกันทั้งหมดมีสำเนาบางส่วนในตำแหน่งบ้าน) คุณสมบัตินี้ถืออยู่ที่ จุดเริ่มต้น (หลังจากจบการวนรอบที่ 1 ของ Caf) และฉันแสดงให้เห็นด้านล่างว่ามันคงอยู่หลังจากแต่ละขั้นตอน
ในขณะที่เราดำเนินการตามอาร์เรย์ความสำเร็จในA[i] != i
ส่วนของการทดสอบแสดงให้เห็นว่าA[i]
อาจซ้ำซ้อนที่ไม่เคยมีมาก่อน หากเราไม่เคยเห็นมาก่อนเราคาดว่าA[i]
ตำแหน่งบ้านจะชี้ไปที่ตัวมันเองนั่นคือสิ่งที่ทดสอบในช่วงครึ่งหลังของif
สภาพ หากเป็นเช่นนั้นเราจะพิมพ์และแก้ไขตำแหน่งบ้านให้ชี้กลับไปที่รายการที่พบครั้งแรกนี้โดยสร้าง "วงจร" 2 ขั้นตอน
จะเห็นว่าการดำเนินการนี้ไม่เปลี่ยนแปลงคงที่เราคิดว่าm = A[i]
สำหรับตำแหน่งโดยเฉพาะอย่างยิ่งความพึงพอใจi
A[i] != i && A[A[i]] == A[i]
เห็นได้ชัดว่าการเปลี่ยนแปลงที่เราทำ ( A[A[i]] = i
) จะทำงานเพื่อป้องกันไม่ให้เกิดเหตุการณ์อื่น ๆ ที่ไม่ใช่บ้านm
จากการส่งออกเป็นรายการซ้ำโดยทำให้เงื่อนไขครึ่งหลังif
ล้มเหลว แต่จะได้ผลเมื่อi
มาถึงที่ตั้งบ้านm
หรือไม่ ใช่มันจะเป็นเพราะตอนนี้แม้ว่าที่ใหม่นี้i
เราพบว่าครึ่งแรกของif
เงื่อนไขนั้นA[i] != i
เป็นจริงครึ่งหลังจะทดสอบว่าสถานที่ที่ชี้ไปนั้นเป็นตำแหน่งบ้านหรือไม่และพบว่าไม่ใช่ ในสถานการณ์นี้เราไม่รู้อีกต่อไปว่าเป็นค่าที่ซ้ำกันm
หรือไม่A[m]
แต่เรารู้ว่าไม่ว่าจะด้วยวิธีใดได้รับการรายงานเนื่องจาก 2 รอบนี้รับประกันว่าจะไม่ปรากฏในผลลัพธ์ของการวนรอบที่ 1 ของ caf (โปรดทราบว่าถ้าอย่างm != A[m]
นั้นอย่างใดอย่างหนึ่งm
และA[m]
เกิดขึ้นมากกว่าหนึ่งครั้งและอีกรายการหนึ่งจะไม่เกิดขึ้นเลย)
a[a[i]]
และข้อ จำกัด ของพื้นที่ O (1) จะบอกเป็นนัยว่าการswap()
ดำเนินการเป็นคีย์