การคำนวณสตริงย่อยทั่วไปที่ยาวที่สุดของสองสตริงโดยใช้อาร์เรย์ต่อท้าย


15

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

  1. รวมทั้งสองสายและBเป็นหนึ่งสายA BABAB
  2. คำนวณอาเรย์ต่อท้ายของAB
  3. คำนวณอาร์เรย์ (คำนำหน้าทั่วไปที่ยาวที่สุด)LP
  4. คำตอบคือค่าที่ใหญ่ที่สุดLP[ผม]

ฉันพยายามที่จะใช้มัน แต่เนื่องจากรายละเอียดการใช้งานไม่ได้กล่าวไว้ (เช่นเมื่อทำการเชื่อมโยงสตริงฉันควรใส่อักขระพิเศษระหว่างพวกเขา ( ) หรือไม่) รหัสของฉันล้มเหลวในหลายกรณีทดสอบ มีคนอธิบายเพิ่มเติมเกี่ยวกับอัลกอริทึมนี้เพิ่มเติมหรือไม่AB

ขอบคุณล่วงหน้า.

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


3
ก่อนที่จะใช้อัลกอริทึมลองเข้าใจว่าทำไมมันถึงใช้งานได้ นั่นอาจช่วยตอบคำถามเช่นวิธีเชื่อมสองสายเข้าด้วยกัน
Yuval Filmus

3
ฉันสงสัยความถูกต้องของอัลกอริทึมนี้ เอาและb c d , วิธีที่ฉันอ่านมันจะคืนค่าa b c dซึ่งผิด adaddad
Khaur

คำตอบ:


20

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

ประการแรกคืออาร์เรย์ส่วนต่อท้าย ( ) ของสตริง อาเรย์ต่อท้ายนั้นโดยทั่วไปแล้วคำต่อท้ายทั้งหมดของสตริงS ที่จัดเรียงตามลำดับพจนานุกรม โดยเฉพาะอย่างยิ่งค่าS [ ผม]แสดงให้เห็นว่าคำต่อท้ายของSเริ่มต้นจากตำแหน่งS [ ผม]เป็นอันดับฉันในการสั่งซื้อพจนานุกรมของคำต่อท้ายทั้งหมดของSSASSA[ผม]SSA[ผม]ผมS

ถัดไปคืออาร์เรย์L C P [ ผม]บ่งบอกถึงความยาวของทั่วไปที่ยาวที่สุดคำนำหน้าระหว่างคำต่อท้ายที่เริ่มต้นจากS [ ฉัน- 1 ]และS [ ผม ] นั่นคือมันติดตามความยาวของคำนำหน้าทั่วไปที่ยาวที่สุดในหมู่คำต่อท้ายที่สองของSเมื่อเรียงตามลำดับพจนานุกรมLPLP[ผม]SA[ผม-1]SA[ผม]S

เป็นตัวอย่างให้พิจารณาสตริงส่วนต่อท้ายในการสั่งซื้อพจนานุกรมจะ{ , , , b , , , }ดังนั้นS = [ 7 , 1S=aaa{a,aaa,aa,aa,aa,a,a}สำหรับอาร์เรย์ 1 ที่จัดทำดัชนี L C Pอาร์เรย์จะเป็น L C P = [ - , 1 , 2 , 0 , 1 , 1 , 0 ]SA=[7,1,4,3,2,5,6]LPLP=[-,1,2,0,1,1,0]

ตอนนี้ได้รับสองสายและBเรา concatenate พวกเขาเป็นS = # Bที่#เป็นตัวละครที่ไม่ได้อยู่ในทั้งสองและB เหตุผลในการเลือกตัวละครดังกล่าวเป็นไปเพื่อที่ว่าเมื่อคำนวณ LCP ของทั้งสองคำต่อท้ายกล่าวว่า# วันที่และการเปรียบเทียบจะแตกออกในตอนท้ายของสตริงแรก (เพราะมันเกิดขึ้นครั้งเดียว สองคำต่อท้ายที่แตกต่างกันจะไม่ได้อยู่ในตำแหน่งเดียวกัน) และจะไม่"ล้น"ในสายอื่นABS=A#B#ABa#dadad

ตอนนี้จะเห็นได้ว่าคุณควรเห็นว่าทำไมคุณต้องเห็นค่าติดต่อกันในอาร์เรย์ (อาร์กิวเมนต์จะขึ้นอยู่กับความขัดแย้งและความจริงที่ว่าคำต่อท้ายในS Aอยู่ในลำดับพจนานุกรม) ตรวจสอบอาร์เรย์L C Pต่อไปเพื่อหาค่าสูงสุดซึ่งคำต่อท้ายสองรายการที่เปรียบเทียบจะไม่ได้อยู่ในสตริงต้นฉบับเดียวกัน หากพวกเขาไม่ได้อยู่ในสตริงเดิมที่เหมือนกัน (อันหนึ่งเริ่มต้นในAและอีกสตริงในB ) ดังนั้นค่าที่ใหญ่ที่สุดคือความยาวของสตริงย่อยทั่วไปที่ใหญ่ที่สุดLPSALPAB

เป็นตัวอย่างให้พิจารณา= และB = จากนั้นS = # ส่วนต่อท้ายที่เรียงลำดับแล้วคือ{ a b c # b c , a b c a b c # b c , b c , b c # b c , b c aA=aaB=S=aa# } S{a#,aa#,,#,a#,,#,a#}
SA=[4,1,8,5,2,9,6,3,7]LP=[-,3,0,2,2,0,1,1,0]

ตอนนี้คุ้มค่ามากที่สุดคือแต่มันเป็นS [ 1 ]และS [ 2 ]ซึ่งทั้งสองเริ่มต้นในสตริง ดังนั้นเราจึงเพิกเฉย ในทางตรงกันข้ามL C P [ 4 ] = 2สำหรับS A [ 3 ] (สอดคล้องกับคำต่อท้ายb cของB ) และS A [ 4 ]LP[2]=3SA[1]SA[2]ALP[4]=2SA[3]BSA[4](สอดคล้องกับคำต่อท้ายของA ) ดังนั้นนี่คือสตริงย่อยทั่วไปที่ยาวที่สุดระหว่างสองสตริง สำหรับการรับสตริงย่อยที่เกิดขึ้นจริงที่คุณจะใช้ความยาว2 (มูลค่าที่ยิ่งใหญ่ที่สุดที่เป็นไปได้L C P ) substring เริ่มต้นจากทั้งS [ 3 ]หรือS [ 4 ]ซึ่งเป็นa#A2 LPSA[3]SA[4]


1
คำอธิบายที่ดีมาก แต่ผมคิดว่าตัวอย่างเป็นผิดบิตต่อท้ายเรียงคือ{#bc,abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}, SA=[7,4,1,8,5,2,9,6,3]และLCP=[−,0,3,0,2,2,0,1,1]
SaúlMartínez Vidals

1

อัลกอริทึมที่คุณพบออนไลน์ไม่ถูกต้องทั้งหมด ดังที่ Paresh กล่าวถึงมันจะล้มเหลวในตัวอย่างที่เขามอบให้

อย่างไรก็ตามหากคุณมั่นใจว่าขณะตรวจสอบ LCP คุณจะตรวจสอบ LCP ของสตริงย่อยของสตริงที่แตกต่างกันเท่านั้น ตัวอย่างเช่นหากคุณกำลังค้นหา LCS ของสตริง A และ B คุณจะต้องตรวจสอบให้แน่ใจว่ารายการ Suffix Array ที่อยู่ติดกันในขณะที่ตรวจสอบ LCP นั้นไม่ได้มาจากสตริงเดียวกัน

รายละเอียดเพิ่มเติมที่นี่


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

0

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

มันจะมีประโยชน์สำหรับการอ้างอิงในอนาคตถ้าคุณโพสต์ลิงค์ไปยังอัลกอริทึม โปรดทราบว่าวิกิพีเดียมีอัลกอริทึมสำหรับสิ่งนี้ในรหัสเทียมและอัลกอริธึมอื่น ๆ อีกมากมาย และมีการนำไปใช้งานในภาษามาตรฐานส่วนใหญ่ทางออนไลน์

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