คำตอบที่ยอดเยี่ยมของ 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()ดำเนินการเป็นคีย์