นี่เป็นO(N)
วิธีง่ายๆที่ใช้O(N)
พื้นที่ ฉันสมมติว่าเรากำลัง จำกัด รายการอินพุตเป็นตัวเลขที่ไม่เป็นลบและเราต้องการค้นหาจำนวนที่ไม่เป็นลบแรกที่ไม่อยู่ในรายการ
- ค้นหาความยาวของรายการ
N
ช่วยบอกว่ามันเป็น
- จัดสรรอาร์เรย์ของบูลีนเริ่มต้นได้ทุก
N
false
- สำหรับแต่ละหมายเลข
X
ในรายการถ้าX
น้อยกว่าN
ตั้งองค์ประกอบของอาร์เรย์X'th
true
- สแกนอาร์เรย์ที่เริ่มต้นจากดัชนีที่กำลังมองหาองค์ประกอบแรกที่เป็น
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))
บิต
- เพื่อกำหนดขนาดอาร์เรย์นับเรียงลำดับความต้องการที่จะทำให้ผ่านครั้งแรกผ่านรายการเพื่อตรวจสอบและ
Xmax
Xmin
- ข้อกำหนดพื้นที่กรณีเลวร้ายที่สุดจึงเป็น
ceiling(log2(N)) * (Xmax - Xmin)
บิต
ในทางตรงกันข้ามอัลกอริทึมที่นำเสนอข้างต้นนั้นต้องการN
บิตในกรณีที่เลวร้ายที่สุดและดีที่สุด
อย่างไรก็ตามการวิเคราะห์นี้นำไปสู่สัญชาตญาณว่าหากอัลกอริทึมทำการส่งผ่านรายการเริ่มต้นโดยมองหาศูนย์ (และนับองค์ประกอบรายการหากจำเป็น) จะให้คำตอบที่เร็วขึ้นโดยไม่ต้องเว้นวรรคเลยหากพบว่าศูนย์ การทำเช่นนี้คุ้มค่าแน่นอนหากมีความเป็นไปได้สูงที่จะพบอย่างน้อยหนึ่งศูนย์ในรายการ และบัตรผ่านพิเศษนี้ไม่ได้เปลี่ยนความซับซ้อนโดยรวม
แก้ไข: ฉันได้เปลี่ยนคำอธิบายของอัลกอริทึมเป็น "อาร์เรย์ของบูลีน" เนื่องจากมีคนพบว่าคำอธิบายดั้งเดิมของฉันโดยใช้บิตและบิตแมปทำให้เกิดความสับสน