นี่เป็นO(N)วิธีง่ายๆที่ใช้O(N)พื้นที่ ฉันสมมติว่าเรากำลัง จำกัด รายการอินพุตเป็นตัวเลขที่ไม่เป็นลบและเราต้องการค้นหาจำนวนที่ไม่เป็นลบแรกที่ไม่อยู่ในรายการ
- ค้นหาความยาวของรายการ
Nช่วยบอกว่ามันเป็น
- จัดสรรอาร์เรย์ของบูลีนเริ่มต้นได้ทุก
Nfalse
- สำหรับแต่ละหมายเลข
Xในรายการถ้าXน้อยกว่าNตั้งองค์ประกอบของอาร์เรย์X'thtrue
- สแกนอาร์เรย์ที่เริ่มต้นจากดัชนีที่กำลังมองหาองค์ประกอบแรกที่เป็น
0 falseหากคุณพบสิ่งแรกfalseที่ดัชนีIแล้วIคือคำตอบ มิฉะนั้น (เช่นเมื่อองค์ประกอบทั้งหมดที่มีtrue) Nคำตอบคือ
ในทางปฏิบัติ "อาร์เรย์ของNบูลีน" อาจถูกเข้ารหัสเป็น "บิตแมป" หรือ "บิตเซ็ต" ที่แสดงเป็นbyteหรือintอาร์เรย์ โดยทั่วไปจะใช้พื้นที่น้อยลง (ขึ้นอยู่กับภาษาโปรแกรม) และช่วยให้การสแกนครั้งแรกfalseทำได้เร็วขึ้น
นี่คือวิธี / เหตุผลที่อัลกอริทึมทำงาน
สมมติว่าตัวเลขในรายการไม่ได้แตกต่างกันหรือที่หนึ่งหรือมากกว่าของพวกเขามีค่ามากกว่าN Nซึ่งหมายความว่าต้องมีอย่างน้อยหนึ่งหมายเลขในช่วง0 .. N - 1ที่ไม่อยู่ในรายการ ดังนั้นปัญหาของการหาจำนวนที่น้อยที่สุดที่ขาดหายไปดังนั้นจึงต้องลดปัญหาการหาจำนวนที่ขาดหายไปที่เล็กที่สุดน้อยกว่า Nนั่นหมายความว่าเราไม่จำเป็นต้องติดตามตัวเลขที่มากกว่าหรือเท่ากับN... เพราะมันจะไม่ใช่คำตอบ
0 .. N - 1ทางเลือกที่จะวรรคก่อนหน้านี้ว่ารายการคือการเปลี่ยนแปลงของตัวเลขจาก ในกรณีนี้ขั้นตอนที่ 3 ชุดองค์ประกอบทั้งหมดของอาร์เรย์การtrueและขั้นตอนที่ 4 บอกเราว่าครั้งแรกที่ "หายไป" Nหมายเลข
ความซับซ้อนในการคำนวณของอัลกอริทึมนั้นO(N)มีค่าคงที่ของสัดส่วนค่อนข้างน้อย ทำให้เส้นตรงสองเส้นผ่านรายการหรือเพียงครั้งเดียวหากทราบว่าความยาวรายการเริ่มต้นด้วย ไม่จำเป็นต้องแสดงถึงการระงับรายการทั้งหมดในหน่วยความจำดังนั้นการใช้หน่วยความจำแบบไม่แสดงอาการของอัลกอริทึมจึงเป็นเพียงสิ่งที่จำเป็นในการแสดงอาร์เรย์ของบูลีน เช่นO(N)บิต
(ในทางตรงกันข้ามอัลกอริทึมที่อาศัยการเรียงลำดับหรือการแบ่งพาร์ติชันในหน่วยความจำจะถือว่าคุณสามารถแสดงรายการทั้งหมดในหน่วยความจำได้ในรูปแบบที่ถามคำถามนี้จะต้องใช้คำO(N)64 บิต)
@Jorn แสดงความคิดเห็นว่าขั้นตอนที่ 1 ถึง 3 เป็นการเปลี่ยนแปลงในการเรียงลำดับการนับ ในแง่หนึ่งเขาพูดถูก แต่ความแตกต่างมีความสำคัญ:
- การเรียงลำดับการนับต้องใช้อาร์เรย์ของ
Xmax - Xminตัวนับ(อย่างน้อย) ซึ่งXmaxเป็นจำนวนที่มากที่สุดในรายการและXminเป็นจำนวนที่น้อยที่สุดในรายการ แต่ละตัวนับจะต้องสามารถเป็นตัวแทนของ N รัฐได้ เช่นสมมติว่าการแทนค่าฐานสองจะต้องมีประเภทจำนวนเต็ม (อย่างน้อย) ceiling(log2(N))บิต
- เพื่อกำหนดขนาดอาร์เรย์นับเรียงลำดับความต้องการที่จะทำให้ผ่านครั้งแรกผ่านรายการเพื่อตรวจสอบและ
XmaxXmin
- ข้อกำหนดพื้นที่กรณีเลวร้ายที่สุดจึงเป็น
ceiling(log2(N)) * (Xmax - Xmin)บิต
ในทางตรงกันข้ามอัลกอริทึมที่นำเสนอข้างต้นนั้นต้องการNบิตในกรณีที่เลวร้ายที่สุดและดีที่สุด
อย่างไรก็ตามการวิเคราะห์นี้นำไปสู่สัญชาตญาณว่าหากอัลกอริทึมทำการส่งผ่านรายการเริ่มต้นโดยมองหาศูนย์ (และนับองค์ประกอบรายการหากจำเป็น) จะให้คำตอบที่เร็วขึ้นโดยไม่ต้องเว้นวรรคเลยหากพบว่าศูนย์ การทำเช่นนี้คุ้มค่าแน่นอนหากมีความเป็นไปได้สูงที่จะพบอย่างน้อยหนึ่งศูนย์ในรายการ และบัตรผ่านพิเศษนี้ไม่ได้เปลี่ยนความซับซ้อนโดยรวม
แก้ไข: ฉันได้เปลี่ยนคำอธิบายของอัลกอริทึมเป็น "อาร์เรย์ของบูลีน" เนื่องจากมีคนพบว่าคำอธิบายดั้งเดิมของฉันโดยใช้บิตและบิตแมปทำให้เกิดความสับสน