ค้นหาจำนวนเต็มที่เล็กที่สุดที่ไม่มีอยู่ในรายการ


87

คำถามสัมภาษณ์ที่น่าสนใจที่เพื่อนร่วมงานของฉันใช้:

สมมติว่าคุณได้รับรายการจำนวนเต็ม 64 บิตที่ไม่ได้ลงนามที่ยาวมากและไม่ได้เรียงลำดับ คุณจะหาจำนวนเต็มที่ไม่ติดลบที่เล็กที่สุดที่ไม่มีอยู่ในรายการได้อย่างไร?

FOLLOW-UP: ตอนนี้มีการเสนอวิธีแก้ปัญหาที่ชัดเจนโดยการเรียงลำดับแล้วคุณสามารถทำได้เร็วกว่า O (n log n) หรือไม่?

การติดตาม: อัลกอริทึมของคุณต้องทำงานบนคอมพิวเตอร์โดยมีหน่วยความจำ 1GB

CLARIFICATION: รายการอยู่ใน RAM แม้ว่าอาจใช้จำนวนมาก คุณได้รับขนาดของรายการโดยพูดว่า N ล่วงหน้า


6
ฉันคิดว่าคุณสามารถละเว้นส่วนที่ไม่เป็นลบได้โดยดูว่าคุณกำลังพูดถึงจำนวนเต็มที่ไม่ได้ลงชื่ออย่างไร
KevenDenen

4
คำถามนี้ค่อนข้างธรรมดาเว้นแต่ว่าฉันจะไม่อยู่ในฐาน IMO แต่อย่างที่คนอื่นพูดถึงมีคำถามที่ต้องถามหรือสมมติฐานที่ควรระบุ
James Black

8
@paxdiablo: นี่เป็นกรณีที่การพูดว่า O (n) ไม่ได้หมายความว่ามาก แม้ว่าคุณจะเก็บอาร์เรย์ 2 ^ 64 บิตไว้บนแท็บเล็ตดินบนเกาะอีสเตอร์และเข้าถึงได้โดยนกพิราบผู้ให้บริการอัลกอริทึมยังคงเป็น O (n)
IJ Kennedy

6
การเปลี่ยนข้อกำหนดหน่วยความจำไปครึ่งทางทำให้คำถามนี้เป็นคำถามสัมภาษณ์ที่ยอดเยี่ยม ;-)
Chris Ballance

1
ฉันคิดว่ามันน่าขบขันที่คำตอบทั้งหมดใช้วิธีแก้ปัญหาทั่วไปแบบเดียวกัน (เรียงลำดับอาร์เรย์และค้นหาค่าแรกที่แบ่งลำดับ) แต่ทั้งหมดใช้การจัดเรียงที่แตกต่างกัน (แก้ไข Quicksort, radix sort, ... ) คำตอบที่ยอมรับจะเทียบเท่ากับการเรียงลำดับที่ทิ้งองค์ประกอบด้านบน N.
Joren

คำตอบ:


121

หากโครงสร้างข้อมูลสามารถกลายพันธุ์ได้และรองรับการเข้าถึงแบบสุ่มคุณสามารถทำได้ในเวลา O (N) และพื้นที่เพิ่มเติม O (1) เพียงแค่ผ่านอาร์เรย์ตามลำดับและสำหรับทุกดัชนีเขียนค่าที่ดัชนีไปยังดัชนีที่ระบุโดยค่าวางค่าใด ๆ ที่ตำแหน่งนั้นไปยังตำแหน่งนั้นซ้ำแล้วทิ้งค่า> N จากนั้นไปที่อาร์เรย์อีกครั้งเพื่อค้นหาจุด โดยที่ค่าไม่ตรงกับดัชนีนั่นคือค่าที่น้อยที่สุดที่ไม่อยู่ในอาร์เรย์ ส่งผลให้มีการเปรียบเทียบ 3N มากที่สุดและใช้พื้นที่ชั่วคราวเพียงไม่กี่ค่าเท่านั้น

# Pass 1, move every value to the position of its value
for cursor in range(N):
    target = array[cursor]
    while target < N and target != array[target]:
        new_target = array[target]
        array[target] = target
        target = new_target

# Pass 2, find first location where the index doesn't match the value
for cursor in range(N):
    if array[cursor] != cursor:
        return cursor
return N

9
nitpick ขนาดเล็ก คุณพลาดกรณีเล็กน้อย: เมื่อรายการคือ {0, ... , N-1} ในกรณีนั้น pass 1 ไม่ทำอะไรเลยและใน pass 2 array [cursor] == cursor สำหรับรายการทั้งหมดในรายการดังนั้นอัลกอริทึมจึงไม่ส่งคืน ดังนั้นคุณต้องมีคำสั่ง 'return N' ในตอนท้าย
Alex

12
โซลูชันของคุณรวมโดเมนและช่วง (เป้าหมายเป็นทั้งค่าและดัชนี) ช่วงนี้ถูก จำกัด โดยพื้นที่เก็บข้อมูลที่มีอยู่ที่ 128M องค์ประกอบ แต่โดเมนมีขนาด 2G จะล้มเหลวด้วยรายการเดียวที่มีค่ามากกว่าจำนวนรายการที่สามารถจัดสรรลงในอาร์เรย์ได้ หากคำถามไม่ได้ระบุคำว่า "ยาวมาก" คำตอบนั้นสวยงามแม้ว่าจะทำลายข้อมูลที่ป้อน การแลกเปลี่ยนพื้นที่เวลามีความชัดเจนมากในปัญหานี้และวิธีแก้ปัญหา O (N) อาจไม่สามารถทำได้ภายใต้ข้อ จำกัด ที่ให้ไว้
Pekka

2
บัตรผ่านที่สองสามารถใช้การค้นหาแบบไบนารีแทนการค้นหาเชิงเส้น
user448810

4
โซลูชันนี้ใช้ได้เฉพาะเมื่อเทียบเคียงช่วงของค่าและดัชนี
Dubby

7
มันจะทำงานได้ดีกับค่าที่มากขึ้น คุณสามารถละเว้นค่าที่ใหญ่กว่าได้เนื่องจากไม่สามารถมีส่วนเกี่ยวข้องกับค่าที่น้อยที่สุดที่ไม่ได้อยู่ในอาร์เรย์ สำหรับตัวอย่างของคุณพาสแรกจะวนซ้ำบนอาร์เรย์โดยไม่สนใจค่าทั้งหมดเนื่องจากเป้าหมาย <N จากนั้นจะส่งกลับ 0 ในการวนซ้ำครั้งแรกของรอบที่สอง
Ants Aasma

89

นี่เป็นO(N)วิธีง่ายๆที่ใช้O(N)พื้นที่ ฉันสมมติว่าเรากำลัง จำกัด รายการอินพุตเป็นตัวเลขที่ไม่เป็นลบและเราต้องการค้นหาจำนวนที่ไม่เป็นลบแรกที่ไม่อยู่ในรายการ

  1. ค้นหาความยาวของรายการ Nช่วยบอกว่ามันเป็น
  2. จัดสรรอาร์เรย์ของบูลีนเริ่มต้นได้ทุก Nfalse
  3. สำหรับแต่ละหมายเลขXในรายการถ้าXน้อยกว่าNตั้งองค์ประกอบของอาร์เรย์X'thtrue
  4. สแกนอาร์เรย์ที่เริ่มต้นจากดัชนีที่กำลังมองหาองค์ประกอบแรกที่เป็น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บิตในกรณีที่เลวร้ายที่สุดและดีที่สุด

อย่างไรก็ตามการวิเคราะห์นี้นำไปสู่สัญชาตญาณว่าหากอัลกอริทึมทำการส่งผ่านรายการเริ่มต้นโดยมองหาศูนย์ (และนับองค์ประกอบรายการหากจำเป็น) จะให้คำตอบที่เร็วขึ้นโดยไม่ต้องเว้นวรรคเลยหากพบว่าศูนย์ การทำเช่นนี้คุ้มค่าแน่นอนหากมีความเป็นไปได้สูงที่จะพบอย่างน้อยหนึ่งศูนย์ในรายการ และบัตรผ่านพิเศษนี้ไม่ได้เปลี่ยนความซับซ้อนโดยรวม


แก้ไข: ฉันได้เปลี่ยนคำอธิบายของอัลกอริทึมเป็น "อาร์เรย์ของบูลีน" เนื่องจากมีคนพบว่าคำอธิบายดั้งเดิมของฉันโดยใช้บิตและบิตแมปทำให้เกิดความสับสน


3
@ adi92 หากขั้นตอนที่ 3 ให้บิตแมปกับบิตทั้งหมดที่ตั้งค่าเป็น 1 รายการจะมีทุกค่าตั้งแต่ 0 ถึง N-1 นั่นหมายถึงจำนวนเต็มที่ไม่ติดลบที่เล็กที่สุดในรายการคือ N หากมีค่าใด ๆ ระหว่าง 0 ถึง N-1 ที่ไม่อยู่ในรายการบิตที่เกี่ยวข้องจะไม่ถูกตั้งค่า ค่าดังกล่าวน้อยที่สุดจึงเป็นคำตอบ
divegeek

4
@ adi92 ในตัวอย่างของคุณรายการจะมี 300 องค์ประกอบ นั่นหมายความว่าหากมีค่าที่ "หายไป" ค่านั้นจะต้องน้อยกว่า 300 การรันอัลกอริทึมเราจะสร้างบิตฟิลด์ที่มี 300 สล็อตจากนั้นตั้งค่าบิตซ้ำ ๆ ในช่อง 1, 2 และ 3 โดยปล่อยให้ทั้งหมด ช่องอื่น ๆ - 0 และ 4 ถึง 299 - ชัดเจน เมื่อสแกนบิตฟิลด์เราจะพบแฟล็กในช่อง 0 ชัดเจนดังนั้นเราจึงรู้ว่า 0 คือคำตอบ
divegeek

4
โปรดทราบว่าอัลกอริทึมนี้อาจเข้าใจง่ายขึ้นโดยไม่ต้องบิดเล็กน้อย: "สร้างอาร์เรย์บูลีนขนาด N" เป็นต้นเมื่อคุณเข้าใจอย่างนั้นแล้วการย้ายไปยังเวอร์ชันบิตเป็นเรื่องง่าย
Jon Skeet

2
เมื่อให้วิธีแก้ปัญหาเชิงนามธรรมให้ใช้วิธีที่ง่ายที่สุดตามแนวคิดที่ได้ผลและอย่าเชี่ยวชาญมากเกินไป โซลูชันของคุณกรีดร้องสำหรับการใช้อาร์เรย์บูลีน (นามธรรม) จึงเรียกมันว่า คุณอาจใช้อาร์เรย์นี้โดยbool[]หรือโดยบิตแมปไม่เกี่ยวข้องกับโซลูชันทั่วไป
Joren

2
ฉันคิดว่าโซลูชันนี้อาจอธิบายได้ดีที่สุดโดย "ใช้การเรียงลำดับการนับที่ไม่คำนึงถึงองค์ประกอบที่อยู่เหนือ N จากนั้นค้นหาองค์ประกอบแรกที่ขาดหายไปโดยทำการค้นหาเชิงเส้นตั้งแต่เริ่มต้น"
Joren

13

เนื่องจากตอนนี้ OP ได้ระบุว่ารายการดั้งเดิมถูกเก็บไว้ใน RAM และคอมพิวเตอร์มีหน่วยความจำเพียง 1GB ฉันจะออกไปข้างนอกและคาดเดาว่าคำตอบคือศูนย์

RAM 1GB หมายความว่ารายการสามารถมีได้สูงสุด 134,217,728 หมายเลขในนั้น แต่มี 2 64 = 18,446,744,073,709,551,616 ตัวเลขที่เป็นไปได้ ดังนั้นความน่าจะเป็นที่ศูนย์อยู่ในรายการคือ 1 ใน 137,438,953,472

ตรงกันข้ามโอกาสที่ฉันจะถูกฟ้าผ่าในปีนี้คือ 1 ใน 700,000 และโอกาสในการโดนอุกกาบาตของฉันคือประมาณ 1 ใน 10 ล้านล้าน ดังนั้นฉันจึงมีแนวโน้มที่จะถูกเขียนลงในวารสารทางวิทยาศาสตร์มากขึ้นประมาณ 10 เท่าเนื่องจากการที่วัตถุท้องฟ้าของฉันเสียชีวิตก่อนวัยอันควรมากกว่าคำตอบที่ไม่ได้เป็นศูนย์


11
การคำนวณของคุณจะถือก็ต่อเมื่อค่ากระจายอย่างสม่ำเสมอและเลือกแบบสุ่ม พวกเขาสามารถสร้างขึ้นตามลำดับได้เช่นกัน
divegeek

1
คุณถูกต้องแน่นอน แต่ฉันทั้งหมดเกี่ยวกับการเพิ่มประสิทธิภาพสำหรับกรณีทั่วไป :)
Barry Brown

10
ดังนั้นโอกาสที่ผู้ถูกสัมภาษณ์จะได้รับเลือกด้วยคำตอบนี้คืออะไร?
Amarghosh

6
คำถามไม่ได้บอกว่าตัวเลขจะถูกเลือกแบบสุ่มอย่างสม่ำเสมอ พวกเขาถูกเลือกโดยผู้ตั้งคำถามนี้ ให้นี้น่าจะเป็นของ 0 เป็นอยู่ในรายการที่เป็นมากขนาดใหญ่กว่า 1 ใน 137,438,953,472 อาจจะใหญ่กว่า 1 ใน 2 :-)
ShreevatsaR

8
@Amarghosh คำตอบสำหรับคำถามนั้นก็เป็นศูนย์เช่นกัน
PeterAllenWebb

10

ดังที่ได้ระบุไว้ในคำตอบอื่น ๆ คุณสามารถเรียงลำดับจากนั้นสแกนจนพบช่องว่าง

คุณสามารถปรับปรุงความซับซ้อนของอัลกอริทึมเป็น O (N) และรักษาพื้นที่ O (N) ได้โดยใช้ QuickSort ที่ปรับเปลี่ยนซึ่งคุณจะกำจัดพาร์ติชันที่ไม่ใช่ตัวเลือกที่เป็นไปได้สำหรับการมีช่องว่าง

  • ในพาร์ติชันเฟสแรกลบรายการที่ซ้ำกัน
  • เมื่อการแบ่งพาร์ติชันเสร็จสมบูรณ์ให้ดูจำนวนรายการในพาร์ติชันด้านล่าง
  • ค่านี้เท่ากับค่าที่ใช้ในการสร้างพาร์ติชันหรือไม่
    • ถ้าเป็นเช่นนั้นแสดงว่าช่องว่างนั้นอยู่ในพาร์ติชันที่สูงขึ้น
      • ดำเนินการต่อด้วย Quicksort โดยไม่สนใจพาร์ติชันด้านล่าง
    • มิฉะนั้นช่องว่างจะอยู่ในพาร์ติชันด้านล่าง
      • ดำเนินการต่อด้วย Quicksort โดยไม่สนใจพาร์ติชันที่สูงกว่า

ซึ่งจะช่วยประหยัดการคำนวณจำนวนมาก


นั่นเป็นสิ่งที่ดีทีเดียว จะถือว่าคุณสามารถคำนวณความยาวของพาร์ติชันได้ในเวลาน้อยกว่าเชิงเส้นซึ่งสามารถทำได้หากเก็บไว้พร้อมกับพาร์ติชันอาร์เรย์ นอกจากนี้ยังถือว่ารายการเดิมถูกเก็บไว้ใน RAM
Barry Brown

2
หากคุณทราบความยาวของรายการคุณยังสามารถเลือกค่าใด ๆ ที่มากกว่า len (รายการ) ได้ ตามหลักการของนกพิราบ 'หลุม' ใด ๆ ต้องน้อยกว่าเลน (รายการ)
divegeek

1
ฉันไม่คิดว่านั่นคือ O (n) ... ประการแรกฉันไม่แน่ใจว่าคุณสามารถลบรายการที่ซ้ำกันได้จนกว่ารายการจะเรียงลำดับอย่างสมบูรณ์ ประการที่สองในขณะที่คุณสามารถรับประกันได้ว่าจะทิ้งพื้นที่ค้นหาครึ่งหนึ่งของการวนซ้ำแต่ละครั้ง (เนื่องจากคุณแบ่งออกเป็นด้านล่างและจุดกึ่งกลาง) คุณยังคงมีการส่งผ่านหลายครั้ง (ขึ้นอยู่กับ n) บนข้อมูลที่ขึ้นอยู่กับ n
แพกซ์ดิอาโบล

1
paxdiablo: คุณสามารถสร้างรายการใหม่ที่มีเฉพาะค่าที่ไม่ซ้ำกันโดยใช้วิธีบิตแมปเช่นเดียวกับที่ Stephen C เสนอ สิ่งนี้ทำงานใน O (n) เวลาและพื้นที่ ฉันไม่แน่ใจว่าจะทำได้ดีกว่านั้นหรือเปล่า
Nic

9

เพื่อแสดงให้เห็นถึงข้อผิดพลาดประการหนึ่งของการO(N)คิดนี่คือO(N)อัลกอริทึมที่ใช้O(1)พื้นที่

for i in [0..2^64):
  if i not in list: return i

print "no 64-bit integers are missing"

1
จะถูกต้อง นี่ไม่ใช่ O (n) เพราะจริงๆแล้วคุณมีสองลูปอยู่ที่นี่ แต่หนึ่งเป็นนัย การพิจารณาว่าค่าที่อยู่ในรายการเป็นการดำเนินการ O (n) หรือไม่และคุณกำลังทำ n ครั้งใน for loop ของคุณ นั่นทำให้ O (n ^ 2)
Nic

6
Nic จะเป็น O (n * N) โดยที่ n คือขนาดของรายการและ N คือขนาดของโดเมน (จำนวนเต็ม 64 บิต) ในขณะที่ N เป็นจำนวนมาก แต่ก็ยังคงเป็นค่าคงที่ดังนั้นความซับซ้อนของปัญหาตามที่ระบุไว้คือ O (n) อย่างเป็นทางการ
Ants Aasma

1
มดฉันยอมรับว่าเป็น O (n N) แต่ N ไม่คงที่ เนื่องจากอัลกอริทึมเสร็จสิ้นเมื่อพบคำตอบจำนวนของการวนซ้ำที่สมบูรณ์ผ่านวงนอกจึงเท่ากับคำตอบซึ่งถูกผูกไว้ด้วยขนาดของรายการ ดังนั้น O (N n) คือ O (n ^ 2) ในกรณีนี้
Will Harris

12
การมองหาตัวเลขในรายการ N องค์ประกอบคือ O (N) อย่างชัดเจน เราทำ 2 ^ 64 ครั้ง ในขณะที่ขนาดใหญ่ 2 ^ 64 เป็นสิ่งคงที่ ดังนั้นอัลกอริทึมคือ C * O (N) ซึ่งยังคงเป็น O (N)
IJ Kennedy

3
ฉันต้องอ่านคำสั่งก่อนหน้าของฉัน ตามคำจำกัดความที่เข้มงวดที่สุดการดำเนินการนี้คือ O (n)
Nic

8

เนื่องจากตัวเลขมีความยาวทั้งหมด 64 บิตเราจึงสามารถใช้การเรียงลำดับแบบเรดิกซ์ซึ่งก็คือ O (n) จัดเรียง 'em จากนั้นสแกน' em จนกว่าคุณจะพบสิ่งที่คุณต้องการ

หากตัวเลขที่น้อยที่สุดเป็นศูนย์ให้สแกนไปข้างหน้าจนกว่าคุณจะพบช่องว่าง ถ้าตัวเลขที่น้อยที่สุดไม่ใช่ศูนย์คำตอบคือศูนย์


จริง แต่ความต้องการหน่วยความจำอาจค่อนข้างรุนแรงสำหรับการเรียงลำดับเรดิกซ์
PeterAllenWebb

1
การเรียงลำดับ Radix จะไม่ทำงานสำหรับชุดข้อมูลขนาดใหญ่มาก แต่การจัดเรียงพาร์ติชันและเรดิกซ์อาจใช้งานได้
DarthVader

5

สำหรับพื้นที่วิธีที่มีประสิทธิภาพและค่าทั้งหมดมีความแตกต่างที่คุณสามารถทำมันในพื้นที่และเวลาO( k ) O( k*log(N)*N )พื้นที่มีประสิทธิภาพและไม่มีการเคลื่อนย้ายข้อมูลและการดำเนินการทั้งหมดเป็นพื้นฐาน (การบวกลบ)

  1. ชุด U = N; L=0
  2. ขั้นแรกแบ่งพื้นที่หมายเลขในkภูมิภาค แบบนี้:
    • 0->(1/k)*(U-L) + L, 0->(2/k)*(U-L) + L, 0->(3/k)*(U-L) + L...0->(U-L) + L
  3. ค้นหาจำนวนตัวเลข ( count{i}) ในแต่ละภูมิภาค ( N*kขั้นตอน)
  4. ค้นหาภูมิภาคแรก ( h) ที่ไม่เต็ม count{h} < upper_limit{h}ซึ่งหมายความว่า ( kขั้นตอน)
  5. ถ้าh - count{h-1} = 1คุณมีคำตอบ
  6. ชุด U = count{h}; L = count{h-1}
  7. ไปที่ 2

สิ่งนี้สามารถปรับปรุงได้โดยใช้การแฮช (ขอบคุณสำหรับ Nic ความคิดนี้)

  1. เหมือนกัน
  2. ขั้นแรกแบ่งพื้นที่หมายเลขในkภูมิภาค แบบนี้:
    • L + (i/k)->L + (i+1/k)*(U-L)
  3. inc count{j} โดยใช้ j = (number - L)/k (if L < number < U)
  4. ค้นหาภูมิภาคแรก ( h) ที่ไม่มีองค์ประกอบ k อยู่
  5. ถ้าcount{h} = 1h คือคำตอบของคุณ
  6. ชุด U = maximum value in region h L = minimum value in region h

O(log(N)*N)นี้จะทำงานใน


ฉันชอบคำตอบนี้มาก มันอ่านยากไปหน่อย แต่มันคล้ายกับสิ่งที่ฉันมีอยู่ในหัวของฉันเมื่อฉันอ่านคำถาม
Nic

ในบางจุดก็เป็นการดีที่จะเปลี่ยนไปใช้โซลูชันบิตแมปนั้นโดย Stephen C. อาจเป็นเมื่อU-L < k
Egon

สิ่งนี้ไม่ทำงานใน O (log (N) * N) แต่ใน O (N) คำตอบของคุณคือการสรุปคำตอบของ @cdiggins และทำงานใน O (N) เนื่องจาก sum (1 / k ** i สำหรับ i ในช่วง (ceil (log_k (n)))) <= 2
Lapinot

ในการวนซ้ำแต่ละครั้งที่คุณใช้หมายเลข O (N) จะใช้การวนซ้ำทั้งหมด O (log_k (N)) ดังนั้น O (log_k (N) * N) == O (บันทึก (N) * N) หมายเลขเดิมไม่ได้ถูกจัดเรียง / จัดเก็บข้อมูลและคุณต้องดำเนินการทั้งหมด
Egon

แต่ถ้าคุณแบ่งรายการต้นฉบับใน k ภูมิภาค (ขนาด n / k) คุณจะเลือกภูมิภาคแรกที่ไม่เต็ม ดังนั้นในการทำซ้ำครั้งต่อไปคุณจะต้องพิจารณาเฉพาะพื้นที่ที่เลือกและแบ่งเป็น k ภูมิภาคใหม่ (ขนาด n / k ** 2) เป็นต้นที่จริงแล้วคุณไม่ได้ทำซ้ำในรายการทั้งหมดทุกครั้ง (มิฉะนั้นจุดของการแบ่งพาร์ติชันคืออะไร ?).
Lapinot

3

ฉันแค่เรียงลำดับแล้ววิ่งไปตามลำดับจนกว่าฉันจะพบช่องว่าง (รวมถึงช่องว่างที่จุดเริ่มต้นระหว่างศูนย์กับตัวเลขแรก)

ในแง่ของอัลกอริทึมสิ่งนี้จะทำได้:

def smallest_not_in_list(list):
    sort(list)
    if list[0] != 0:
        return 0
    for i = 1 to list.last:
        if list[i] != list[i-1] + 1:
            return list[i-1] + 1
    if list[list.last] == 2^64 - 1:
        assert ("No gaps")
    return list[list.last] + 1

แน่นอนถ้าคุณมีหน่วยความจำมากกว่า CPU ฮึดฮัดคุณสามารถสร้าง bitmask ของค่า 64 บิตที่เป็นไปได้ทั้งหมดและตั้งค่าบิตสำหรับทุกหมายเลขในรายการ จากนั้นมองหา 0 บิตแรกใน bitmask นั้น นั่นทำให้มันเป็นการดำเนินการ O (n) ในแง่ของเวลา แต่ค่อนข้างแพงในแง่ของความต้องการหน่วยความจำ :-)

ฉันสงสัยว่าคุณสามารถปรับปรุง O (n) ได้เนื่องจากฉันไม่เห็นวิธีการทำที่ไม่เกี่ยวข้องกับการดูตัวเลขแต่ละตัวอย่างน้อยหนึ่งครั้ง

อัลกอริทึมสำหรับสิ่งนั้นจะเป็นไปตาม:

def smallest_not_in_list(list):
    bitmask = mask_make(2^64) // might take a while :-)
    mask_clear_all (bitmask)
    for i = 1 to list.last:
        mask_set (bitmask, list[i])
    for i = 0 to 2^64 - 1:
        if mask_is_clear (bitmask, i):
            return i
    assert ("No gaps")

จากคำอธิบายดูเหมือนว่าจะกีดกัน 0 ไปยังองค์ประกอบแรกเนื่องจากมีค่าน้อยที่สุดที่ไม่อยู่ในรายการ แต่นั่นเป็นข้อสันนิษฐานที่ฉันตั้งไว้ฉันอาจจะผิดก็ได้
James Black

ความคิดของฉันคือถ้าลำดับการจัดเรียงเป็น 4,5,6 ดังนั้น 0 จะน้อยที่สุดที่ไม่อยู่ในรายการ
paxdiablo

ฉันคาดว่า 2, 3, 5, คำตอบควรเป็น 4 แต่ฉันคิดผิด
James Black

คำถามที่ OP ควรได้รับคำตอบ พื้นที่ค้นหาเป็น "จำนวนเต็ม 64 บิตทั้งหมดที่ไม่ได้ลงชื่อ" หรือ "ตัวเลขทั้งหมดระหว่างค่าต่ำสุดและสูงสุดในรายการ" หรือไม่
paxdiablo

ฉันยอมรับว่าในกรณีที่เลวร้ายที่สุดคุณต้องดูอย่างน้อยหนึ่งครั้งเว้นแต่จะถูกจัดเรียงในต้นไม้ไบนารีแล้ว
James Black

2

จัดเรียงรายการดูองค์ประกอบแรกและองค์ประกอบที่สองและเริ่มขึ้นจนกว่าจะมีช่องว่าง


ขึ้นอยู่กับว่าคุณกำหนดอย่างไรไม่อยู่ในรายการ
James Black

@PeterAllenWebb - จะมี แต่ตัวเลขเรียงลำดับแบบสุ่มหรือเรียงลำดับ?
James Black

1

คุณสามารถทำได้ใน O (n) เวลาและ O (1) พื้นที่เพิ่มเติมแม้ว่าปัจจัยที่ซ่อนอยู่จะค่อนข้างมาก นี่ไม่ใช่วิธีที่ใช้ได้จริงในการแก้ปัญหา แต่ก็น่าสนใจ

สำหรับทุกจำนวนเต็ม 64 บิตที่ไม่ได้ลงชื่อ (เรียงลำดับจากน้อยไปหามาก) จะวนซ้ำในรายการจนกว่าคุณจะพบจำนวนเต็มที่เป้าหมายหรือคุณไปถึงจุดสิ้นสุดของรายการ หากคุณไปถึงจุดสิ้นสุดของรายการจำนวนเต็มเป้าหมายคือจำนวนเต็มที่น้อยที่สุดที่ไม่อยู่ในรายการ หากคุณมาถึงจุดสิ้นสุดของจำนวนเต็ม 64 บิตทุก ๆ จำนวนเต็ม 64 บิตจะอยู่ในรายการ

นี่คือฟังก์ชัน Python:

def smallest_missing_uint64(source_list):
    the_answer = None

    target = 0L
    while target < 2L**64:

        target_found = False
        for item in source_list:
            if item == target:
                target_found = True

        if not target_found and the_answer is None:
            the_answer = target

        target += 1L

    return the_answer

ฟังก์ชันนี้ไม่มีประสิทธิภาพโดยเจตนาที่จะรักษาไว้ O (n) โปรดสังเกตว่าฟังก์ชันจะตรวจสอบจำนวนเต็มเป้าหมายแม้ว่าจะพบคำตอบแล้วก็ตาม หากฟังก์ชันส่งคืนทันทีที่พบคำตอบจำนวนครั้งที่วงนอกวิ่งจะถูกผูกไว้ด้วยขนาดของคำตอบซึ่งถูกผูกไว้ด้วย n การเปลี่ยนแปลงนั้นจะทำให้เวลาทำงาน O (n ^ 2) แม้ว่าจะเร็วขึ้นมากก็ตาม


จริง. มันน่าขบขันที่อัลกอริทึมบางส่วนที่เป็น O (1) space และ O (n) เวลาล้มเหลวในทางปฏิบัติกับคำถามนี้
PeterAllenWebb

1

ขอบคุณ egon, swilden และ Stephen C สำหรับแรงบันดาลใจของฉัน อันดับแรกเราทราบขอบเขตของมูลค่าเป้าหมายเนื่องจากไม่สามารถมากกว่าขนาดของรายการได้ นอกจากนี้รายการ 1GB สามารถมีจำนวนเต็ม 64 บิตได้มากที่สุด 134217728 (128 * 2 ^ 20)

ส่วนการแฮช
ฉันขอเสนอให้ใช้การแฮชเพื่อลดพื้นที่การค้นหาของเราลงอย่างมาก ขั้นแรกให้สแควร์รูทขนาดของรายการ สำหรับรายการ 1GB นั่นคือ N = 11,586 ตั้งค่าอาร์เรย์จำนวนเต็มขนาด N วนซ้ำตามรายการและนำสแควร์รูท * ของแต่ละหมายเลขที่คุณพบเป็นแฮชของคุณ ในตารางแฮชของคุณเพิ่มตัวนับสำหรับแฮชนั้น จากนั้นทำซ้ำผ่านตารางแฮชของคุณ ที่เก็บข้อมูลแรกที่คุณพบซึ่งไม่เท่ากับขนาดสูงสุดจะกำหนดพื้นที่ค้นหาใหม่ของคุณ


ตอนนี้ตั้งค่าบิตแมปปกติให้เท่ากับขนาดของพื้นที่ค้นหาใหม่ของคุณแล้ววนซ้ำอีกครั้งผ่านรายการต้นทางกรอกข้อมูลในบิตแมปเมื่อคุณพบแต่ละหมายเลขในพื้นที่ค้นหาของคุณ เมื่อคุณทำเสร็จแล้วบิตแรกที่ยังไม่ได้ตั้งค่าในบิตแมปจะให้คำตอบแก่คุณ

สิ่งนี้จะเสร็จสมบูรณ์ในเวลา O (n) และช่องว่าง O (sqrt (n))

(* คุณสามารถใช้บางอย่างเช่นการขยับบิตเพื่อทำสิ่งนี้ให้มีประสิทธิภาพมากขึ้นและเพียงแค่เปลี่ยนจำนวนและขนาดของที่เก็บข้อมูลตามนั้น)


1
ฉันชอบแนวคิดในการแบ่งพื้นที่การค้นหาออกเป็นที่เก็บข้อมูล Root-N เพื่อลดการใช้หน่วยความจำ แต่รายการที่ซ้ำกันในรายการจะทำลายวิธีนี้ ฉันสงสัยว่ามันสามารถแก้ไขได้หรือไม่
PeterAllenWebb

คุณพูดถูกฉันละเลยที่จะพิจารณารายการที่ซ้ำกัน ฉันไม่แน่ใจว่าสามารถแก้ไขได้
Nic

1

ถ้ามีตัวเลขที่ขาดหายไปเพียงตัวเดียวในรายการตัวเลขวิธีที่ง่ายที่สุดในการค้นหาหมายเลขที่หายไปคือการรวมชุดและลบแต่ละค่าในรายการ ค่าสุดท้ายคือจำนวนที่ขาดหายไป


ใช่. นั่นเป็นคำถามสัมภาษณ์คลาสสิกอีกคำถามหนึ่ง
PeterAllenWebb

1
ง่ายยิ่งไปกว่านั้นคือการ XOR ตัวเลขในรายการรวมกัน XOR ตัวเลขในช่วงเข้าด้วยกันและ XOR ผลลัพธ์ด้วยกัน
John Kurlak

1
 int i = 0;
            while ( i < Array.Length)
            {

                if (Array[i] == i + 1)
                {
                    i++;
                }

                if (i < Array.Length)
                {
                    if (Array[i] <= Array.Length)
                    {//SWap

                        int temp = Array[i];
                        int AnoTemp = Array[temp - 1];
                        Array[temp - 1] = temp;
                        Array[i] = AnoTemp;

                    }
                    else
                       i++;



                }
            }

            for (int j = 0; j < Array.Length; j++)
            {
                if (Array[j] > Array.Length)
                {
                    Console.WriteLine(j + 1);
                    j = Array.Length;
                }
                else
                    if (j == Array.Length - 1)
                        Console.WriteLine("Not Found !!");

            }
        }

1

เราสามารถใช้ตารางแฮชเพื่อเก็บตัวเลข เมื่อตัวเลขทั้งหมดเสร็จสิ้นให้รันตัวนับจาก 0 จนกว่าเราจะพบค่าต่ำสุด แฮชที่ดีพอสมควรจะแฮชและจัดเก็บในเวลาคงที่และเรียกคืนในเวลาคงที่

for every i in X         // One scan Θ(1)
   hashtable.put(i, i);  // O(1)

low = 0;

while (hashtable.get(i) <> null)   // at most n+1 times
   low++;

print low;

กรณีที่เลวร้ายที่สุดหากมีnองค์ประกอบในอาร์เรย์และ{0, 1, ... n-1}ในกรณีที่คำตอบจะรับได้ที่ยังคงเก็บรักษาไว้nO(n)


1

นี่คือคำตอบของฉันที่เขียนด้วย Java:

แนวคิดพื้นฐาน: 1- วนรอบอาร์เรย์โดยทิ้งจำนวนบวกเลขศูนย์และลบที่ซ้ำกันในขณะที่สรุปส่วนที่เหลือรับจำนวนบวกสูงสุดเช่นกันและเก็บตัวเลขบวกที่ไม่ซ้ำกันไว้ในแผนที่

2- คำนวณผลรวมเป็นสูงสุด * (สูงสุด + 1) / 2

3- ค้นหาความแตกต่างระหว่างผลรวมที่คำนวณในขั้นตอนที่ 1 และ 2

4- วนซ้ำอีกครั้งจาก 1 ถึงค่าต่ำสุดของ [ผลต่างผลรวมสูงสุด] และส่งคืนตัวเลขแรกที่ไม่ได้อยู่ในแผนที่ที่เติมในขั้นตอนที่ 1

public static int solution(int[] A) {
    if (A == null || A.length == 0) {
        throw new IllegalArgumentException();
    }

    int sum = 0;
    Map<Integer, Boolean> uniqueNumbers = new HashMap<Integer, Boolean>();
    int max = A[0];
    for (int i = 0; i < A.length; i++) {
        if(A[i] < 0) {
            continue;
        }
        if(uniqueNumbers.get(A[i]) != null) {
            continue;
        }
        if (A[i] > max) {
            max = A[i];
        }
        uniqueNumbers.put(A[i], true);
        sum += A[i];
    }
    int completeSum = (max * (max + 1)) /  2;
    for(int j = 1; j <= Math.min((completeSum - sum), max); j++) {
        if(uniqueNumbers.get(j) == null) { //O(1)
            return j;
        }
    }
    //All negative case
    if(uniqueNumbers.isEmpty()) {
        return 1;
    }
    return 0;
}

0

ดังที่ Stephen C ชี้ให้เห็นอย่างชาญฉลาดคำตอบจะต้องเป็นตัวเลขที่น้อยกว่าความยาวของอาร์เรย์ จากนั้นฉันจะหาคำตอบโดยการค้นหาไบนารี สิ่งนี้จะเพิ่มประสิทธิภาพในกรณีที่เลวร้ายที่สุด (ดังนั้นผู้สัมภาษณ์ไม่สามารถจับคุณในสถานการณ์ทางพยาธิวิทยา 'จะเกิดอะไรขึ้นถ้า') ในการสัมภาษณ์ให้ชี้ให้เห็นว่าคุณกำลังทำสิ่งนี้เพื่อเพิ่มประสิทธิภาพสำหรับกรณีที่เลวร้ายที่สุด

วิธีใช้การค้นหาแบบไบนารีคือการลบจำนวนที่คุณต้องการออกจากแต่ละองค์ประกอบของอาร์เรย์และตรวจสอบผลลัพธ์ที่เป็นลบ


0

ฉันชอบการประเมินแบบ "เดาศูนย์" หากตัวเลขเป็นแบบสุ่มศูนย์มีความเป็นไปได้สูง หาก "ผู้ตรวจสอบ" ตั้งรายการแบบไม่สุ่มให้เพิ่มรายการหนึ่งแล้วเดาอีกครั้ง:

LowNum=0
i=0
do forever {
  if i == N then leave /* Processed entire array */
  if array[i] == LowNum {
     LowNum++
     i=0
     }
   else {
     i++
   }
}
display LowNum

กรณีที่เลวร้ายที่สุดคือ n * N ที่มี n = N แต่ในทางปฏิบัติ n มีแนวโน้มสูงที่จะเป็นจำนวนน้อย (เช่น 1)


0

ฉันไม่แน่ใจว่าฉันได้รับคำถาม แต่ถ้าสำหรับรายการ 1,2,3,5,6 และหมายเลขที่หายไปคือ 4 ตัวเลขที่หายไปสามารถพบได้ใน O (n) โดย: (n + 2) (n + 1) / 2- (n + 1) n / 2

แก้ไข: ขอโทษฉันเดาว่าเมื่อคืนฉันคิดเร็วเกินไป อย่างไรก็ตามส่วนที่สองควรถูกแทนที่ด้วย sum (list) ซึ่งเป็นที่ที่ O (n) มา สูตรแสดงแนวคิดเบื้องหลัง: สำหรับ n จำนวนเต็มตามลำดับผลรวมควรเป็น (n + 1) * n / 2 หากมีจำนวนที่ขาดหายไปผลรวมจะเท่ากับผลรวมของจำนวนเต็มตามลำดับ (n + 1) ลบด้วยจำนวนที่ขาดหายไป

ขอขอบคุณที่ชี้ให้เห็นความจริงที่ว่าฉันนึกถึงสิ่งที่เป็นกลางๆ


1
ฉันไม่เห็นว่ามันจะได้ผลในตอนแรก ในกรณีของคุณ n = 5 และ formulera จะได้รับการแก้ไขไม่ว่าหมายเลขใดจะหายไป
sisve

Simon: ตอนนี้คุณช่วยลบการโหวตลงตามการแก้ไขของฉันได้ไหม
Codism

0

มด Aasma ทำได้ดีมาก! ฉันคิดหาคำตอบประมาณ 15 นาทีและได้คำตอบอย่างอิสระในแนวความคิดที่คล้ายกันกับคุณ:

#define SWAP(x,y) { numerictype_t tmp = x; x = y; y = tmp; }
int minNonNegativeNotInArr (numerictype_t * a, size_t n) {
    int m = n;
    for (int i = 0; i < m;) {
        if (a[i] >= m || a[i] < i || a[i] == a[a[i]]) {
            m--;
            SWAP (a[i], a[m]);
            continue;
        }
        if (a[i] > i) {
            SWAP (a[i], a[a[i]]);
            continue;
        }
        i++;
    }
    return m;
}

m หมายถึง "เอาต์พุตสูงสุดที่เป็นไปได้ในปัจจุบันโดยให้สิ่งที่ฉันรู้เกี่ยวกับอินพุต i ตัวแรกและไม่มีอะไรอื่นเกี่ยวกับค่าจนกว่ารายการที่ m-1"

ค่าของ m นี้จะถูกส่งกลับก็ต่อเมื่อ (a [i], ... , a [m-1]) เป็นการเปลี่ยนแปลงค่า (i, ... , m-1) ดังนั้นถ้า [i]> = m หรือถ้า [i] <i หรือถ้า a [i] == a [a [i]] เรารู้ว่า m เป็นเอาต์พุตที่ไม่ถูกต้องและต้องต่ำกว่าอย่างน้อยหนึ่งองค์ประกอบ ดังนั้นการลดค่า m และการสลับ [i] กับ [m] เราสามารถเรียกคืนได้

ถ้าสิ่งนี้ไม่เป็นความจริง แต่เป็น [i]> ฉันก็รู้ว่า a [i]! = a [a [i]] เรารู้ว่าการสลับ [i] กับ [a [i]] จะเพิ่มจำนวนองค์ประกอบ ในสถานที่ของตนเอง

มิฉะนั้น [i] จะต้องเท่ากับ i ซึ่งในกรณีนี้เราสามารถเพิ่มขึ้นได้ฉันรู้ว่าค่าทั้งหมดที่สูงถึงและรวมดัชนีนี้เท่ากับดัชนี

ข้อพิสูจน์ว่าสิ่งนี้ไม่สามารถเข้าสู่ลูปที่ไม่มีที่สิ้นสุดได้ถูกปล่อยให้เป็นแบบฝึกหัดสำหรับผู้อ่าน :)


0

ส่วนDafnyจากคำตอบของ Ants แสดงให้เห็นว่าเหตุใดอัลกอริทึมแบบแทนที่อาจล้มเหลว requiresสภาพก่อนอธิบายว่าค่าของแต่ละรายการจะต้องไม่ไปไกลเกินกว่าขอบเขตของอาร์เรย์

method AntsAasma(A: array<int>) returns (M: int)
  requires A != null && forall N :: 0 <= N < A.Length ==> 0 <= A[N] < A.Length;
  modifies A; 
{
  // Pass 1, move every value to the position of its value
  var N := A.Length;
  var cursor := 0;
  while (cursor < N)
  {
    var target := A[cursor];
    while (0 <= target < N && target != A[target])
    {
        var new_target := A[target];
        A[target] := target;
        target := new_target;
    }
    cursor := cursor + 1;
  }

  // Pass 2, find first location where the index doesn't match the value
  cursor := 0;
  while (cursor < N)
  {
    if (A[cursor] != cursor)
    {
      return cursor;
    }
    cursor := cursor + 1;
  }
  return N;
}

วางรหัสลงในโปรแกรมตรวจสอบความถูกต้องโดยมีและไม่มีส่วนforall ...คำสั่งเพื่อดูข้อผิดพลาดในการตรวจสอบ ข้อผิดพลาดที่สองเป็นผลมาจากการที่ผู้ตรวจสอบไม่สามารถสร้างเงื่อนไขการสิ้นสุดสำหรับลูป Pass 1 ได้ การพิสูจน์สิ่งนี้เหลืออยู่สำหรับคนที่เข้าใจเครื่องมือดีกว่า


0

นี่คือคำตอบใน Java ที่ไม่แก้ไขอินพุตและใช้เวลา O (N) และ N บิตบวกค่าใช้จ่ายของหน่วยความจำคงที่เล็กน้อย (โดยที่ N คือขนาดของรายการ):

int smallestMissingValue(List<Integer> values) {
    BitSet bitset = new BitSet(values.size() + 1);
    for (int i : values) {
        if (i >= 0 && i <= values.size()) {
            bitset.set(i);
        }
    }
    return bitset.nextClearBit(0);
}

0
def solution(A):

index = 0
target = []
A = [x for x in A if x >=0]

if len(A) ==0:
    return 1

maxi = max(A)
if maxi <= len(A):
    maxi = len(A)

target = ['X' for x in range(maxi+1)]
for number in A:
    target[number]= number

count = 1
while count < maxi+1:
    if target[count] == 'X':
        return count
    count +=1
return target[count-1] + 1

รับ 100% สำหรับวิธีแก้ปัญหาข้างต้น


0

1) กรองลบและศูนย์

2) เรียง / แตกต่าง

3) เยี่ยมชมอาร์เรย์

ความซับซ้อน : O (N) หรือ O (N * log (N))

ใช้Java8

public int solution(int[] A) {
            int result = 1;
    boolean found = false;
    A = Arrays.stream(A).filter(x -> x > 0).sorted().distinct().toArray();
    //System.out.println(Arrays.toString(A));
    for (int i = 0; i < A.length; i++) {
        result = i + 1;
        if (result != A[i]) {
            found = true;
            break;
        }
    }
    if (!found && result == A.length) {
        //result is larger than max element in array
        result++;
    }
    return result;
}

0

unordered_set สามารถใช้เพื่อเก็บจำนวนบวกทั้งหมดจากนั้นเราสามารถวนซ้ำจาก 1 ไปยังความยาวของ unordered_set และดูตัวเลขแรกที่ไม่เกิดขึ้น

int firstMissingPositive(vector<int>& nums) {

    unordered_set<int> fre;
    // storing each positive number in a hash.
    for(int i = 0; i < nums.size(); i +=1)
    {
        if(nums[i] > 0)
            fre.insert(nums[i]);
     }

    int i = 1;
    // Iterating from 1 to size of the set and checking 
    // for the occurrence of 'i'

    for(auto it = fre.begin(); it != fre.end(); ++it)
    {
        if(fre.find(i) == fre.end())
            return i;
        i +=1;
    }

    return i;
}

0

แก้ปัญหาผ่านจาวาสคริปต์พื้นฐาน

var a = [1, 3, 6, 4, 1, 2];

function findSmallest(a) {
var m = 0;
  for(i=1;i<=a.length;i++) {
    j=0;m=1;
    while(j < a.length) {
      if(i === a[j]) {
        m++;
      }
      j++;
    }
    if(m === 1) {
      return i;
    }
  }
}

console.log(findSmallest(a))

หวังว่านี่จะช่วยสำหรับใครบางคน


0

ด้วย python มันไม่ได้มีประสิทธิภาพมากที่สุด แต่ถูกต้อง

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import datetime

# write your code in Python 3.6

def solution(A):
    MIN = 0
    MAX = 1000000
    possible_results = range(MIN, MAX)

    for i in possible_results:
        next_value = (i + 1)
        if next_value not in A:
            return next_value
    return 1

test_case_0 = [2, 2, 2]
test_case_1 = [1, 3, 44, 55, 6, 0, 3, 8]
test_case_2 = [-1, -22]
test_case_3 = [x for x in range(-10000, 10000)]
test_case_4 = [x for x in range(0, 100)] + [x for x in range(102, 200)]
test_case_5 = [4, 5, 6]
print("---")
a = datetime.datetime.now()
print(solution(test_case_0))
print(solution(test_case_1))
print(solution(test_case_2))
print(solution(test_case_3))
print(solution(test_case_4))
print(solution(test_case_5))


0

สิ่งนี้สามารถช่วยได้:

0- A is [5, 3, 2, 7];
1- Define B With Length = A.Length;                            (O(1))
2- initialize B Cells With 1;                                  (O(n))
3- For Each Item In A:
        if (B.Length <= item) then B[Item] = -1                (O(n))
4- The answer is smallest index in B such that B[index] != -1  (O(n))

สิ่งนี้แตกต่างจากคำตอบของ Stephen Cหรือไม่? อย่างไร?
greybeard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.