รับ 100 ตัวเลขสูงสุดจากรายการที่ไม่มีที่สิ้นสุด


53

เพื่อนคนหนึ่งของฉันถูกถามคำถามสัมภาษณ์นี้ -

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

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

จากนั้นคำถามก็ถูกขยายออกไป -

"คุณแน่ใจได้หรือไม่ว่าคำสั่งสำหรับการแทรกควรเป็น O (1)? เป็นไปได้หรือไม่"

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

ฉันคิดว่าต้นไม้ไบนารีที่สมดุล แต่ถึงแม้คุณจะไม่ได้รับการแทรกด้วยลำดับที่ 1 ดังนั้นคำถามเดียวกันที่ฉันมีตอนนี้ ต้องการทราบว่ามีโครงสร้างข้อมูลใด ๆ ที่สามารถทำการแทรกในลำดับ 1 สำหรับปัญหาข้างต้นหรือเป็นไปไม่ได้เลย


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

36
@EdoDodo - และหลังจากการดำเนินการคุณจะรู้ได้อย่างไรว่าตัวเลขต่ำสุดใหม่คืออะไร?
Damien_The_Unbeliever

19
จัดเรียงรายการ [O (100 * บันทึก (100)) = O (1)] หรือทำการค้นหาเชิงเส้นผ่านอย่างน้อย [O (100) = O (1)] เพื่อรับจำนวนต่ำสุดใหม่ รายการของคุณมีขนาดคงที่ดังนั้นการดำเนินการทั้งหมดเหล่านี้จึงเป็นเวลาที่แน่นอน
Random832

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

27
asymptoticคำสั่งของการดำเนินการเป็นที่น่าสนใจเท่านั้นเมื่อขนาดของปัญหาสามารถเจริญเติบโตได้โดยไม่ต้องถูกผูกไว้ ไม่ชัดเจนจากคำถามของคุณว่าปริมาณใดเติบโตขึ้นอย่างไม่มีข้อ จำกัด ดูเหมือนว่าคุณกำลังถามว่าใบสั่ง asymptotic สำหรับปัญหาที่ขนาดถูก จำกัด ที่ 100; นั่นไม่ใช่คำถามที่สมเหตุสมผลที่จะถาม สิ่งที่จะต้องเติบโตอย่างไม่มีที่สิ้นสุด หากคำถามคือ "คุณสามารถทำเพื่อรักษาคะแนนสูงสุดไม่ใช่ 100 อันดับแรกในเวลา O (1) หรือไม่" ถ้าอย่างนั้นคำถามก็สมเหตุสมผล
Eric Lippert

คำตอบ:


35

สมมุติว่า k คือจำนวนตัวเลขสูงสุดที่คุณต้องการรู้ (100 ในตัวอย่างของคุณ) จากนั้นคุณสามารถเพิ่มหมายเลขใหม่O(k)ได้เช่นO(1)กัน O(k*g) = O(g) if k is not zero and constantเพราะ


6
O (50) คือ O (n) ไม่ใช่ O (1) การแทรกลงในรายการความยาว N ในเวลา O (1) หมายความว่าเวลาไม่ขึ้นอยู่กับค่าของ N นั่นหมายความว่าถ้า 100 กลายเป็น 10,000, 50 จะต้องไม่กลายเป็น 5000

18
@hamstergene - แต่ในกรณีของคำถามนี้คือNขนาดของรายการที่เรียงลำดับหรือจำนวนรายการที่ถูกประมวลผลแล้วหรือยัง? หากคุณประมวลผล 10,000 รายการและเก็บ 100 รายการสูงสุดในรายการหรือคุณประมวลผลรายการ 1000000000 และเก็บ 100 รายการสูงสุดในรายการที่เรียงลำดับต้นทุนการแทรกในรายการนั้นจะยังคงเหมือนเดิม
Damien_The_Unbeliever

6
@hamstergene: ในกรณีนี้คุณมีพื้นฐานที่ไม่ถูกต้อง ในการเชื่อมโยงวิกิพีเดียของคุณมีคุณสมบัติ ( O(k*g) = O(g) if k not zero and constant"คูณด้วยค่าคง"): O(50*1) = O(1)=>
duedl0r

9
ฉันคิดว่า duedl0r ถูกต้อง มาลดปัญหาและบอกว่าคุณต้องการเพียงค่าต่ำสุดและค่าสูงสุดเท่านั้น นี่คือ O (n) เพราะค่า minumum และค่าสูงสุดคือ 2 หรือไม่? (n = 2) หมายเลข 2 เป็นส่วนหนึ่งของคำจำกัดความของปัญหา เป็นค่าคงที่ดังนั้นมันจึงเป็น ak ใน O (k * บางอย่าง) ที่เทียบเท่ากับ O (บางสิ่งบางอย่าง)
xanatos

9
@hamstergene: คุณกำลังพูดถึงฟังก์ชั่นอะไร? ค่า 100 ดูเหมือนจะค่อนข้างคงที่สำหรับฉัน ..
duedl0r

19

เก็บรายการที่ไม่เรียงลำดับ การพิจารณาว่าการแทรกหมายเลขใหม่จะใช้เวลานานขึ้นหรือไม่ แต่การแทรกจะเป็น O (1)


7
ฉันคิดว่านี่จะทำให้คุณได้รับรางวัลsmart-aleckถ้าไม่มีอะไรอื่น * 8 ')
Mark Booth

4
@Emilio คุณถูกต้องทางเทคนิค - และแน่นอนว่าเป็นประเภทที่ถูกต้องที่สุด ...
Gareth

1
แต่คุณสามารถรักษาตัวเลขที่ต่ำที่สุดของคุณได้ 100 จากนั้นคุณสามารถตัดสินใจได้ว่าคุณจะต้องใส่ใน O (1) หรือไม่ จากนั้นเฉพาะเมื่อคุณใส่ตัวเลขคุณต้องค้นหาหมายเลขต่ำสุดใหม่ แต่นั่นเกิดขึ้นได้ยากกว่าการตัดสินใจแทรกหรือไม่ซึ่งเกิดขึ้นกับหมายเลขใหม่ทุกหมายเลข
Andrei Vajna II

12

มันง่ายมาก ขนาดของรายการค่าคงที่ดังนั้นเวลาเรียงลำดับของรายการจึงเป็นค่าคงที่ การดำเนินการที่ดำเนินการในเวลาคงที่กล่าวกันว่าเป็น O (1) ดังนั้นการเรียงลำดับรายการคือ O (1) สำหรับรายการขนาดคงที่


9

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

Worst = CheckTime + EnterTime

ถัดไปหากการกระจายตัวของตัวเลขเป็นแบบสุ่มต้นทุนเฉลี่ยจะลดจำนวนที่คุณมีมากขึ้น ตัวอย่างเช่นโอกาสที่คุณจะต้องป้อนหมายเลข 101 ลงในชุดสูงสุดคือ 100/101 โอกาสสำหรับหมายเลขที่ 1,000 จะเป็น 1/10 และโอกาสสำหรับหมายเลขที่ n จะเป็น 100 / n ดังนั้นสมการของเราสำหรับค่าเฉลี่ยจะเป็น:

Average = CheckTime + EnterTime / n

ดังนั้นเมื่อnเข้าใกล้อนันต์CheckTimeเท่านั้นจึงสำคัญ:

Average = CheckTime

ถ้าตัวเลขที่มีการผูกพันCheckTimeเป็นค่าคงที่และทำให้มันเป็น O (1)เวลา

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

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


ยกเว้นว่ารายการนั้นจะเป็นแบบสุ่มถ้าเป็นรายการของตัวเลขที่เพิ่มขึ้นเรื่อย ๆ
dan_waterworth

@dan_waterworth: หากรายการไม่มีที่สิ้นสุดเป็นสิ่งที่ผิดกฎหมายและเพิ่งจะเพิ่มขึ้นเรื่อย ๆ (อัตราต่อรองที่จะเป็น 1 / ∞!) นั่นจะเหมาะกับสถานการณ์กรณีที่เลวร้ายที่สุดของCheckTime + EnterTimeแต่ละหมายเลข สิ่งนี้จะสมเหตุสมผลหากไม่มีการ จำกัด จำนวนและดังนั้นCheckTimeและEnterTimeทั้งสองจะเพิ่มขึ้นอย่างน้อยลอการิทึมเนื่องจากการเพิ่มขนาดของตัวเลข
Briguy37

1
ตัวเลขไม่ได้สุ่มมีกฎเกณฑ์ใด ๆ มันไม่มีเหตุผลที่จะพูดถึงเรื่องราคา
dan_waterworth

@dan_waterworth: ตอนนี้คุณพูดมาแล้วสองครั้งแล้ว คุณได้สิ่งนี้มาจากไหน นอกจากนี้ฉันเชื่อว่าคุณยังสามารถใช้สถิติกับตัวเลขที่กำหนดขึ้นเองโดยเริ่มต้นจากกรณีแบบสุ่มและปรับปรุงความแม่นยำของข้อมูลดังกล่าวเมื่อคุณรู้เพิ่มเติมเกี่ยวกับผู้ชี้ขาด ตัวอย่างเช่นถ้าคุณเป็นผู้ชี้ขาดมันจะมีโอกาสมากขึ้นในการเลือกตัวเลขที่เพิ่มมากขึ้นกว่าถ้าพูดว่าฉันเป็นผู้ชี้ขาด;)
Briguy37

7

อันนี้เป็นเรื่องง่ายถ้าคุณรู้ว่าต้นไม้ไบนารีกอง heap แบบไบนารีสนับสนุนการแทรกในเวลาคงที่เฉลี่ย O (1) และให้คุณเข้าถึงองค์ประกอบ x แรกได้อย่างง่ายดาย


ทำไมต้องจัดเก็บองค์ประกอบที่คุณไม่ต้องการ (ค่าที่ต่ำเกินไป) ดูเหมือนว่าอัลกอริทึมที่กำหนดเองจะเหมาะสมกว่า ไม่บอกว่าคุณไม่สามารถ 'ไม่เพิ่ม' ค่าเมื่อค่าเหล่านั้นไม่สูงกว่าค่าต่ำสุด
Steven Jeuris

ฉันไม่รู้ปรีชาบอกฉันว่าฮีป (มีรสชาติ) สามารถดึงสิ่งนี้ออกมาได้ดีทีเดียว ไม่ได้หมายความว่าเขาจะต้องให้องค์ประกอบทั้งหมดทำเช่นนั้น ฉันไม่ได้ทำการวิจัย แต่มัน "รู้สึกถูก" (TM)
Rig

3
ฮีปสามารถปรับเปลี่ยนเพื่อละทิ้งสิ่งที่ต่ำกว่าระดับ mth บางส่วน (สำหรับฮีปไบนารีและ k = 100, m จะเท่ากับ 7 เนื่องจากจำนวนโหนด = 2 ^ m-1) สิ่งนี้จะทำให้ช้าลง แต่ก็ยังคงถูกตัดจำหน่ายตลอดเวลา
พลูโต

3
หากคุณใช้ min-heap แบบไบนารี (เพราะด้านบนเป็นค่าต่ำสุดซึ่งคุณกำลังตรวจสอบอยู่ตลอดเวลา) และคุณพบหมายเลขใหม่> min คุณต้องลบองค์ประกอบด้านบนออกก่อนจึงจะสามารถแทรกองค์ประกอบใหม่ได้ . การลบองค์ประกอบด้านบน (นาที) จะเป็น O (logN) เพราะคุณต้องข้ามทุกระดับของต้นไม้หนึ่งครั้ง ดังนั้นจึงเป็นความจริงทางเทคนิคว่าเม็ดมีดเป็นค่าเฉลี่ย O (1) เพราะในทางปฏิบัติมันยังคงเป็น O (logN) ทุกครั้งที่คุณพบตัวเลข> นาที
Scott Whitlock

1
@Plutor คุณกำลังรับประกันบางอย่างว่า heap แบบไบนารีไม่ให้คุณ การมองภาพมันเป็นต้นไม้ไบนารีมันอาจเป็นได้ว่าแต่ละองค์ประกอบในสาขาด้านซ้ายมีขนาดเล็กกว่าองค์ประกอบใด ๆ ในสาขาที่ถูกต้อง แต่คุณสมมติว่าองค์ประกอบที่เล็กที่สุดอยู่ใกล้กับรูทมากที่สุด
Peter Taylor

6

หากคำถามที่ผู้สัมภาษณ์ตั้งใจถามจริง ๆ “ เราสามารถตรวจสอบให้แน่ใจว่าตัวเลขที่เข้ามาแต่ละตัวนั้นถูกประมวลผลในเวลาที่แน่นอน” แล้วตามที่หลายคนชี้ไปแล้ว (เช่นดูคำตอบของ @ duedl0r) คำตอบของเพื่อนของคุณนั้นเป็น O (1) และ มันจะเป็นเช่นนั้นแม้ว่าเขาจะใช้รายการที่ไม่เรียงลำดับหรือใช้การเรียงลำดับฟองหรืออะไรก็ตาม ในกรณีนี้คำถามไม่สมเหตุสมผลนักเว้นแต่เป็นคำถามที่ยุ่งยากหรือคุณจำผิด

ฉันคิดว่าคำถามของผู้สัมภาษณ์มีความหมายว่าเขาไม่ได้ถามว่าจะทำบางสิ่งให้เป็น O (1) ซึ่งเห็นได้ชัดมากแล้ว

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

สิ่งแรกที่อยู่ในใจคือการเรียงลำดับการนับซึ่งจะซื้อความซับซ้อนของ O (1) เวลาต่อหมายเลขสำหรับปัญหา Top-N- สำหรับราคาการใช้พื้นที่ O (m) โดยที่mคือความยาวของช่วงของตัวเลขที่เข้ามา . ใช่มันเป็นไปได้


4

ใช้คิวลำดับความสำคัญต่ำสุดที่ใช้กับฮีโบฟีนาชีซึ่งมีเวลาแทรกอย่างต่อเนื่อง:

1. Insert first 100 elements into PQ
2. loop forever
       n = getNextNumber();
       if n > PQ.findMin() then
           PQ.deleteMin()
           PQ.insert(n)

4
"การดำเนินการลบและลบการทำงานขั้นต่ำในO(log n)เวลาตัดจำหน่าย"ดังนั้นนี้จะยังคงมีผลในการO(log k)ที่kเป็นจำนวนเงินของรายการที่จะจัดเก็บ
Steven Jeuris

1
นี่ไม่แตกต่างจากคำตอบของ Emilioที่ได้รับการขนานนามว่า "smart-aleck award" ตั้งแต่ลบ minทำงานในO (log n) (อ้างอิงจาก Wikipedia)
Nicole

@Renesis คำตอบของ Emilio จะเป็น O (k) เพื่อค้นหาขั้นต่ำเหมืองของฉันคือ O (บันทึก k)
Gabe Moothart

1
@Gabe ยุติธรรมเพียงพอฉันแค่หมายถึงในหลักการ กล่าวอีกนัยหนึ่งถ้าคุณไม่ใช้เวลา 100 คงที่คำตอบนี้จะไม่ต่อเนื่องเหมือนกัน
นิโคล

@Renesis ฉันลบคำสั่ง (ไม่ถูกต้อง) ออกจากคำตอบแล้ว
Gabe Moothart

2

งานชัดเจนเพื่อค้นหาอัลกอริทึมที่เป็น O (1) ในความยาว N ของรายการตัวเลขที่ต้องการ ดังนั้นไม่สำคัญว่าคุณต้องการหมายเลข 100 อันดับแรกหรือ 10,000 หมายเลขเวลาแทรกควรเป็น O (1)

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

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

  2. รับหมายเลขใหม่ x จากสตรีมแบบสุ่ม

  3. มันสูงกว่าจำนวนต่ำสุดที่บันทึกไว้ล่าสุดหรือไม่ ใช่ => ขั้นตอนที่ 4 ไม่ => ขั้นตอนที่ 2

  4. กดตารางแฮชด้วยหมายเลขที่เพิ่งถ่าย มีรายการไหม? ใช่ => ขั้นตอนที่ 5 ไม่ => ใช้หมายเลขใหม่ x-1 และทำซ้ำขั้นตอนนี้ (นี่คือการค้นหาแบบเส้นตรงที่ลดลงเพียงแค่อดทนกับฉันที่นี่สิ่งนี้สามารถปรับปรุงได้และฉันจะอธิบายวิธี)

  5. ด้วยองค์ประกอบลิสต์ที่เพิ่งได้รับจากตารางแฮชให้ใส่หมายเลขใหม่หลังอิลิเมนต์ในรายการที่ลิงก์ (และอัปเดตแฮช)

  6. ใช้หมายเลขต่ำสุดที่บันทึกไว้ (และลบออกจากแฮช / รายการ)

  7. กดตารางแฮชด้วยหมายเลขที่เพิ่งถ่าย มีรายการไหม? ใช่ => ขั้นตอนที่ 8 ไม่ => ใช้หมายเลขใหม่ l + 1 และทำซ้ำขั้นตอนนี้ (นี่เป็นการค้นหาเชิงเส้นที่ง่ายขึ้น)

  8. ด้วยจำนวนการบวกจำนวนกลายเป็นหมายเลขต่ำสุดใหม่ ไปที่ขั้นตอนที่ 2

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

ส่วนแทรกที่นี่คือ O (1) การค้นหาที่กล่าวถึงคือฉันเดาว่า O (ความแตกต่างระหว่างตัวเลขโดยเฉลี่ย) ความแตกต่างเฉลี่ยเพิ่มขึ้นตามขนาดของพื้นที่หมายเลข แต่ลดลงตามความยาวที่ต้องการของรายการตัวเลข

กลยุทธ์การค้นหาเชิงเส้นค่อนข้างแย่ถ้าพื้นที่จำนวนมาก (เช่นสำหรับ 4 ไบต์ชนิด int, 0 ถึง 2 ^ 32-1) และ N = 100 ในการหลีกเลี่ยงปัญหาด้านประสิทธิภาพนี้คุณสามารถเก็บชุดแฮชเทเบิ้ลแบบขนานได้โดยที่ตัวเลขจะถูกปัดเศษให้มีขนาดที่สูงขึ้น (เช่น 1s, 10s, 100s, 1000s) เพื่อสร้างคีย์ที่เหมาะสม ด้วยวิธีนี้คุณสามารถเลื่อนเกียร์ขึ้นและลงเพื่อทำการค้นหาที่ต้องการได้รวดเร็วยิ่งขึ้น ประสิทธิภาพกลายเป็น O (บันทึกหมายเลขลำดับ) ฉันคิดว่าซึ่งคงที่เช่น O (1) ด้วย

เพื่อให้ชัดเจนยิ่งขึ้นลองจินตนาการว่าคุณมีหมายเลข 197 อยู่ในมือ คุณกดแฮชของตาราง 10s ด้วย '190' มันจะถูกปัดเศษเป็นสิบที่ใกล้ที่สุด อะไร? ไม่เลยคุณลงไปใน 10 วินาทีจนกว่าคุณจะพูดว่า 120 จากนั้นคุณสามารถเริ่มต้นที่ 129 ใน hashtable 1s จากนั้นลอง 128, 127 จนกระทั่งคุณตีอะไรบางอย่าง ตอนนี้คุณได้พบว่าที่ไหนในรายการที่เชื่อมโยงเพื่อใส่หมายเลข 197 ขณะที่ใส่ไว้คุณต้องอัปเดต hashtable 1s ด้วยรายการ 197, hashtable 10s ด้วยหมายเลข 190, 100s กับ 100 ฯลฯ ขั้นตอนส่วนใหญ่ คุณต้องทำที่นี่ 10 ครั้งบันทึกของช่วงตัวเลข

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

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


1
การค้นหาจะต้องเป็นส่วนหนึ่งของฟังก์ชั่นแทรก - ไม่ใช่ฟังก์ชั่นอิสระ เนื่องจากการค้นหาของคุณคือ O (n) ฟังก์ชั่นแทรกของคุณจึงเป็น O (n)
Kirk Broadhurst

ไม่ได้ใช้กลยุทธ์ที่ฉันอธิบายซึ่งมีการใช้แฮชเทเบิลเพื่อสำรวจพื้นที่จำนวนอย่างรวดเร็วมากขึ้นนั่นคือ O (1) โปรดอ่านคำตอบของฉันอีกครั้ง
เบเนดิกต์

1
@ เบเนดิกต์คำตอบของคุณบอกอย่างชัดเจนว่ามันมีการค้นหาเชิงเส้นในขั้นตอนที่ 4 และ 7 การค้นหาเชิงเส้นไม่ใช่ O (1)
Peter Taylor

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

@Benedict คุณถูกต้อง - ไม่รวมการค้นหาคำตอบของคุณคือ O (1) น่าเสียดายที่โซลูชันนี้ใช้ไม่ได้หากไม่มีการค้นหา
Kirk Broadhurst

1

เราสามารถสันนิษฐานได้ว่าตัวเลขนั้นเป็นชนิดข้อมูลคงที่เช่นจำนวนเต็ม? ถ้าเป็นเช่นนั้นให้นับทุกหมายเลขเดียวที่เพิ่ม นี่เป็นการดำเนินการ O (1)

  1. ประกาศอาร์เรย์ที่มีองค์ประกอบมากเท่าที่มีตัวเลขที่เป็นไปได้:
  2. อ่านแต่ละหมายเลขตามที่สตรีม
  3. นับจำนวน เพิกเฉยหากตัวเลขนั้นได้รับการนับ 100 ครั้งแล้วเพราะคุณไม่ต้องการมัน การทำเช่นนี้จะป้องกันไม่ให้มีการรับข้อมูลมากเกินจำนวนครั้ง
  4. ทำซ้ำจากขั้นตอนที่ 2

รหัส VB.Net:

Const Capacity As Integer = 100

Dim Tally(Integer.MaxValue) As Integer ' Assume all elements = 0
Do
    Value = ReadValue()
    If Tally(Value) < Capacity Then Tally(Value) += 1
Loop

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

Dim List(Capacity) As Integer
Dim ListCount As Integer = 0
Dim Value As Integer = Tally.Length - 1
Dim ValueCount As Integer = 0
Do Until ListCount = List.Length OrElse Value < 0
    If Tally(Value) > ValueCount Then
        List(ListCount) = Value
        ValueCount += 1
        ListCount += 1
    Else
        Value -= 1
        ValueCount = 0
    End If
Loop
Return List

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


1

จำนวนร้อยจะถูกเก็บไว้ในอาเรย์อย่างง่ายดายขนาด 100 ต้นไม้รายการหรือชุดใด ๆ นั้นมีจำนวนมากเกินไป

หากตัวเลขที่เข้ามานั้นสูงกว่าค่าต่ำสุด (= ล่าสุด) ในอาร์เรย์ให้เรียกใช้ผ่านรายการทั้งหมด เมื่อคุณพบที่แรกที่มีขนาดเล็กกว่าหมายเลขใหม่ของคุณ (คุณสามารถใช้การค้นหาแฟนซีทำเช่นนั้น) วิ่งผ่านส่วนที่เหลือของอาร์เรย์ผลักดันแต่ละรายการ "ลง" โดยหนึ่ง

เนื่องจากคุณเก็บรายการเรียงลำดับตั้งแต่ต้นคุณไม่จำเป็นต้องเรียกใช้อัลกอริทึมการเรียงลำดับเลย นี่คือ O (1)


0

คุณสามารถใช้ Binary Max-Heap คุณต้องติดตามตัวชี้ไปยังโหนดขั้นต่ำ (ซึ่งอาจไม่ทราบ / null)

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

จากนั้นเมื่อคุณได้รับหมายเลขใหม่:

if(minimumNode == null)
{
    minimumNode = findMinimumNode();
}
if(newNumber > minimumNode.Value)
{
    heap.Remove(minimumNode);
    minimumNode = null;
    heap.Insert(newNumber);
}

น่าเสียดายที่findMinimumNodeO (n) และคุณต้องเสียค่าใช้จ่ายหนึ่งครั้งต่อการแทรก (แต่ไม่ใช่ระหว่างการใส่ :) การลบโหนดขั้นต่ำและการใส่โหนดใหม่นั้นโดยเฉลี่ยแล้ว O (1) เพราะพวกมันจะมีแนวโน้มที่ด้านล่างของฮีป

ไปทางอื่นด้วย Binary Min-Heap min นั้นอยู่ด้านบนสุดซึ่งยอดเยี่ยมสำหรับการค้นหา min เพื่อเปรียบเทียบ แต่ sucks เมื่อคุณต้องแทนที่ค่าต่ำสุดด้วยตัวเลขใหม่ที่> min นั่นเป็นเพราะคุณต้องลบโหนดขั้นต่ำ (เสมอ O (logN)) แล้วใส่โหนดใหม่ (ค่าเฉลี่ย O (1)) ดังนั้นคุณยังคงมี O (logN) ซึ่งดีกว่า Max-Heap แต่ไม่ใช่ O (1)

แน่นอนถ้า N คงที่คุณจะมี O (1) เสมอ :)

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