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


9

ฉันต้องการกรองรายการจำนวนเต็มอย่างมีประสิทธิภาพสำหรับรายการที่ซ้ำกันในแบบที่ต้องเก็บชุดผลลัพธ์เท่านั้น

วิธีนี้สามารถเห็นได้:

  • เรามีช่วงของจำนวนเต็ม S={1,,N} กับ N ใหญ่ (พูด 240)
  • เรามีฟังก์ชั่น f:SS มีการชนหลายครั้ง (ภาพมีการกระจายอย่างสม่ำเสมอ S)
  • เราต้องไปเก็บของ f[S], นั่นคือ {f(x)|xS}

ฉันมีการประมาณความแม่นยำ (ความน่าจะเป็น) ของสิ่งที่ |f[S]| คือและสามารถจัดสรรโครงสร้างข้อมูลล่วงหน้าได้ (พูด |f[S]|230)

ฉันมีความคิดเล็กน้อย แต่ฉันไม่แน่ใจว่าอะไรจะเป็นวิธีที่ดีที่สุด:

  • บิตเซตไม่อยู่ในคำถามเนื่องจากชุดอินพุตไม่พอดีกับหน่วยความจำ
  • ตารางแฮช แต่ (1) ต้องการหน่วยความจำโอเวอร์เฮดประมาณ 150% |f[S]| และ (2) ตารางจะต้องถูกสำรวจเมื่อสร้างขึ้นซึ่งต้องใช้เวลาเพิ่มเติมเนื่องจากหน่วยความจำโอเวอร์เฮด
  • การเรียงลำดับ "ในทันที" โดยเฉพาะอย่างยิ่งกับ O(N)ความซับซ้อน (เรียงลำดับที่ไม่เปรียบเทียบ) เกี่ยวกับการที่ผมไม่แน่ใจว่าสิ่งที่เป็นความแตกต่างที่สำคัญระหว่างการจัดเรียงถังและflashsort
  • อาร์เรย์แบบง่าย ๆ ที่มีแผนภูมิการค้นหาแบบไบนารี แต่สิ่งนี้ต้องการ O(Nlog|f[S]|) เวลา.
  • บางทีการใช้ตัวกรอง Bloomหรือโครงสร้างข้อมูลที่คล้ายกันอาจมีประโยชน์ในการผ่อนปรน (โดยมีผลบวกเป็นเท็จ) ของปัญหา

บางคำถามใน StackOverflow ดูเหมือนจะแก้ไขปัญหาด้วยการจัดเรียงของสิ่งนี้ ( /programming/12240997/sorting-array-in-on-run-time , /programming/3951547/java - หาแบบซ้ำซ้อน ) แต่ดูเหมือนว่าจะไม่ตรงกับความต้องการของฉัน


2
คุณจำเป็นต้องระบุ f [S] (ไม่ว่ามันจะเป็นอะไร) หรือจะบอกได้อย่างรวดเร็วว่ามี x อยู่ในนั้นหรือไม่?
Gilles 'หยุดความชั่วร้าย'

@Gilles: ฉันเชื่อว่าเนื่องจากไม่มีโครงสร้างที่ชัดเจนสามารถพบได้ใน f [S] โซลูชั่นทั้งสองจึงเทียบเท่ากัน
doc

ตัวเลขของคุณจะไม่เพิ่มขึ้น ภาพที่คาดหวังของฟังก์ชั่นสุ่มในโดเมนที่มีขนาดN คร่าวๆ (11/e)N. ปัญหาอีกอย่างก็คือการผ่าน256จะใช้เวลานานเกินไปจนกว่าคุณจะมีซูเปอร์คอมพิวเตอร์หรือคลัสเตอร์ขนาดใหญ่ในการกำจัดของคุณ
Yuval Filmus

1
เวลาสำหรับแผนผังการค้นหาแบบไบนารีจะเป็นอย่างไร O(Nlog|f[S]|)ซึ่งอาจหรืออาจจะไม่ใกล้เคียง O(NlogN)ในทางปฏิบัติ แต่ยังมีความแม่นยำมากกว่า
jmad

1
กับ N256จะไม่ห้ามอัลกอริธึมเชิงเส้นตรงหรือไม่ (จากการคำนวณของฉันแม้ว่าคุณจะพิจารณาองค์ประกอบหนึ่งของSใน 1 นาโนวินาทีมันจะใช้เวลา 2 ปี!
Aryabhata

คำตอบ:


1

ทำไมไม่ถังขยะและโซ่?

แนวคิดคือการเก็บจำนวนเต็มบวกที่สามารถแทนได้ด้วย n=k+m บิตในอาร์เรย์ A ของ 2k รายการที่แสดงช่วงของค่า: รายการ A[y], y0หมายถึงช่วง [2my,2m(y+1)1]. สำหรับคนใด1x<2n เราอาจเขียน x=2my+z ที่ไหน y มี k บิตและ z มี mเกร็ด พยายามที่จะเก็บz (ไม่ x!) ที่สถานที่ตั้ง y:

  • เมื่อไหร่ A[y]=z ไม่ทำอะไรเลย: x ซ้ำซ้อน

  • เมื่อไหร่ A[y] ไม่มีการเตรียมการจัดเก็บ z ที่ A[y].

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

ในตอนท้าย f(S) ง่ายต่อการกู้คืนโดยการวนซ้ำผ่านรายการเริ่มต้นของ A และ - เพียงแค่เชื่อมสอง bitstrings - ประกอบกันอีกครั้ง z พบได้ที่สถานที่ y (โดยตรงหรือภายในห่วงโซ่อ้างอิงมี) เป็นค่าเดิม x=2my+z.

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

พื้นที่จัดเก็บข้อมูลที่จำเป็นสูงสุด 2n บิตสำหรับ A และ 22k บิตสำหรับโซ่ (สมมติว่า mk) นี่เป็นพื้นที่ที่จำเป็นสำหรับการจัดเก็บ2k ค่าของ nบิตแต่ละ หากคุณมั่นใจในความสม่ำเสมอคุณสามารถจัดสรรที่เก็บสำหรับโซ่ได้ หากความไม่เป็นเอกเทศเป็นไปได้คุณอาจต้องการเพิ่มk และสนับสนุนการจัดเก็บโซ่อย่างเต็มที่

อีกทางเลือกหนึ่งในการคิดเกี่ยวกับการแก้ปัญหานี้คือมันเป็นตารางแฮชที่มีฟังก์ชั่นแฮชที่ดีเป็นพิเศษk บิตที่สำคัญที่สุด) และด้วยเหตุนี้เราจึงจำเป็นต้องจัดเก็บที่สำคัญที่สุดเท่านั้น m=nk บิตในตาราง

มีวิธีการซ้อนทับการจัดเก็บข้อมูลสำหรับกลุ่มที่มีการจัดเก็บข้อมูลสำหรับ A แต่ดูเหมือนจะไม่คุ้มค่ากับความรำคาญเพราะมันจะไม่ประหยัดมากนัก (สมมติว่า m มีขนาดเล็กกว่ามาก k) ช่องว่างและจะทำให้รหัสยากขึ้นในการพัฒนาตรวจแก้จุดบกพร่องและบำรุงรักษา


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

ดังนั้นนี่คือ Θ(n2)บนอินพุตที่กระจายไม่ได้ ฉันไม่เห็นว่ามันมีประสิทธิภาพแค่ไหน
einpoklum

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