รายการคำที่ยาวที่สุดพร้อมตัวอักษรเริ่มต้นและตัวอักษรที่ตรงกัน


11

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

คุณจะได้รับการป้อนคำ 100 คำในภาษาอังกฤษแบบสุ่ม คุณต้องค้นหาสตริงคำที่ยาวที่สุดที่ตัวอักษรตัวสุดท้ายในคำเดียวตรงกับตัวอักษรตัวแรกในคำถัดไป คุณสามารถใช้แต่ละคำได้ครั้งเดียวเท่านั้น

ตัวอย่างเช่นหากคุณได้รับคำว่า "cat", "dog", "that" สตริงที่ยาวที่สุดที่คุณสามารถทำได้คือ "cat -> that" หากคุณได้รับคำว่า "mouse", "moose", "unicorn" สตริงที่ยาวที่สุดที่คุณสามารถสร้างได้จะเป็นเพียงหนึ่งคำ (เนื่องจากไม่มีลิงก์คำเหล่านั้น) หากคุณได้คำว่า "bird", "dish", "harb" สตริงที่ยาวที่สุดที่คุณสามารถทำได้คือ "harb -> bird -> dish" (หรือ "dish -> harb -> bird" หรือ "bird - > dish -> harb ")

ฉันคิดว่าการสร้างแบบจำลองนี้เป็นกราฟวงกลมกำกับ แต่ละโหนดจะเป็นเพียงคำเดียวโดยจุดยอดจะไปที่แต่ละคำ / โหนดที่เริ่มต้นด้วยตัวอักษรคำนี้ลงท้ายด้วย

+-------+         \ +------+
|  cat  |-----------| that |
+-------+         / +------+
    |                  |
   \|/                 |
+-------+ /            |
|  the  |--------------+
+-------+ \

ปัญหานี้ดูเหมือนจะเป็นการค้นหาเส้นทางที่ยาวที่สุดซึ่งก็คือ NP-Hard

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


4
ด้วย 100 คำคุณจะได้รับ (อย่างน้อย) 100! = 9.332622e + 157 ชุดค่าผสม โชคดีที่ฉันคิดว่าเพื่อนของคุณกำลังดึงขาของคุณบอกว่านี่เป็นเรื่องง่าย
Martin Wickman

1
แต่จำนวนชุดค่าผสมที่เป็นไปได้นั้นน้อยกว่ามากเนื่องจากโดยเฉลี่ยแล้วคำเดียวจะเชื่อมโยงกับคำอื่น ๆ ประมาณ 6 หรือ 7 คำเท่านั้น
เครื่องมือ Abe

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

4
เพื่อความสนุกฉันได้เขียนรหัสการค้นหาที่โหดร้าย (ตามที่ @kevincline ชี้ให้เห็น) ใน Ruby ( gist.github.com/anonymous/6225361 ) ด้วย 100 คำใช้เวลาเพียง 96 วินาทีเท่านั้น ( gist.github.com/anonymous/6225364 ) และนี่คือสคริปต์ที่ไม่มีประสิทธิภาพสูงที่ไม่ได้รับการเพิ่มประสิทธิภาพการตีความภาษารวดเร็วและสกปรก ดังนั้นด้วยคำเพียง 100 คำแม้กระทั่งการบังคับใช้เดรัจฉานที่ช้าในระยะเวลาอันสั้น รหัสของฉันไม่ได้สร้างกราฟแบบวนรอบจากนั้นค้นหาผ่านมันจะสร้างเส้นทางแบบวนซ้ำทุกเส้นทางที่เป็นไปได้เริ่มต้นจากแต่ละคำและติดตามเส้นทางที่ยาวที่สุด
เบ็นลี

3
ปัญหาระบุว่ามี 100 คำ ฉันคิดว่านี่หมายความว่าคุณสามารถใช้โซลูชันการเขียนโปรแกรมแบบไดนามิกซึ่งกล่าวถึงในบทความที่คุณอ้างถึง
Julien Guertault

คำตอบ:


5

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

นี่คือวิธีที่ฉันจะแนะนำการแก้ปัญหานี้:

  1. สำหรับแต่ละคำในรายการให้นับการเชื่อมต่อที่เป็นไปได้และการเชื่อมต่อออก
  2. ยกเลิกคำใด ๆ ที่มี 0 ins และ 0 ลึกหนาบาง
  3. ระบุชุดเริ่มต้นของ "คำเริ่มต้น" ที่มีจำนวน ins และ outs ต่ำที่สุดและ outs ต้องมากกว่า 0
  4. คำเริ่มต้นแต่ละคำจะได้รับสำเนาการทำงานการเชื่อมต่อ ins / outs ของตนเอง รูปแบบนี้เป็นหัวของห่วงโซ่
  5. สำหรับแต่ละกลุ่มระบุรายการของ "คำถัดไป" ตาม:
    • อักษรตัวสุดท้ายของตัวเริ่มต้นหรือคำก่อนหน้า
    • จำนวนต่ำสุดของการเชื่อมต่อ ins และ outs (อีกครั้ง outs ต้องมากกว่า 0)
  6. สำหรับแต่ละnext wordให้ทำซ้ำขั้นตอนที่ 5 จนกว่าเชนจะสิ้นสุดลง

โปรดทราบว่า:

  • คุณจะต้องติดตามความยาวของโซ่และมีกลไกระดับโลกเพื่อระบุโซ่ที่ยาวที่สุด

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

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

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

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

ตัวอย่างเช่น:

{dog, gopher, alpha, cube, elegant, this, that, bart}

dog     0, 1
gopher  1, 0
alpha   0, 0
cube    0, 1
elegant 1, 2
this    3, 0
that    2, 1
bart    0, 2

//alpha is dropped with 0 in and 0 out.
//two candidates found: dog, cube

//chain 1
dog => gopher
//chain 2
cube => elegant => that => this

//Note 1: the following chain won't occur due to selection rules
//that takes priority over this because of output count
cube => elegant => this

//Note 2: this chain won't occur either due to selection rules
bart => that => this

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

@BenLee - ฉันเป็นวิศวกรซอฟต์แวร์ ฉันไม่เคยรับประกันรหัสของฉัน :-) อย่างจริงจังแม้ว่าฉันไม่ทราบคำตอบสำหรับคำถามของคุณ ทฤษฎีเซตและทักษะการพิสูจน์ทางคณิตศาสตร์ของฉันอ่อนแอดังนั้นฉันจึงไม่มีวิธีใดนอกเหนือจากการประเมินเชิงประจักษ์ในการตรวจสอบอัลกอริทึมของฉัน ฉันไม่แน่ใจว่าปัญหานี้เป็นปัญหาที่ยากมาก แต่ฉันไม่สามารถตรวจสอบการอ้างสิทธิ์ได้เช่นกัน ถ้ามันไม่ได้เป็น NP- ยากก็ควรจะมีวิธีการตรวจสอบอัลกอริทึม

2
สิ่งที่เกี่ยวกับรายการคำเช่นนี้: "dog, gopher, bun, nun, noon, nub" อัลกอริทึมจะเลือกรายการที่ยาวที่สุดอย่างไม่ถูกต้องเป็น "dog -> gopher" เมื่อจริง ๆ แล้วมันเป็นการรวมกันของ "bun, nun, เที่ยง, nub"
เครื่องมือ Abe

1
@AbeTool - ตัวอย่างที่ดีที่นั่น ฉันจะเพิ่มการวนซ้ำอีกครั้ง (หรือสองครั้ง) เพื่ออนุญาตสำหรับ "การป้อนค่าต่ำสุด> = 1" และ "การส่งออกต่ำสุด> = 1" จากนั้น

2
ฉันไม่คิดว่ามันจะแก้ปัญหาในทุกกรณี ฉันคิดว่านี่เป็นโซลูชันประเภท "สูงสุดในพื้นที่"
เครื่องมือ Abe

3

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

update @ GlenH7 ฉันแก้ไขคำถามที่คล้ายกันใน www.hackerearth / jda เมื่อเร็ว ๆ นี้มีเครื่องหมายสัมพัทธ์ที่เกี่ยวข้องกับวิธีการแก้ปัญหาที่ดีที่สุดและฉันได้คะแนนสูงสุดด้วยการอนุมัติต่อไปนี้ -

รับรายการคำศัพท์ ค้นหาห่วงโซ่ที่ยาวที่สุดที่สามารถเกิดขึ้นได้โดยพวกเขา ห่วงโซ่ใช้ได้ถ้าทุกคำเริ่มต้นด้วยตัวอักษร * สิ้นสุดที่ท้ายคำสุดท้าย

Approch =

1) สร้างกราฟของตัวอักษรเป็นจุดยอดและคำเป็นขอบ แทนที่การใช้ขอบหลายอันให้ใช้อันที่มีน้ำหนักเท่ากับจำนวนขอบ

2) ค้นหาองค์ประกอบที่เชื่อมต่ออย่างยิ่งของกราฟที่มีขอบสูงสุด ยกเลิกขอบอื่นชั่วคราว

3) สำหรับจุดสุดยอดแต่ละอันทำให้มันมีค่าเท่ากับจำนวนของมัน

4) ตอนนี้วงจรออยเลอร์มีอยู่ในกราฟ หามัน

5) ตอนนี้ในกราฟที่เหลืออยู่ (กราฟ wrt orignal ค้นหาเส้นทางที่ยาวที่สุดที่มีจุดยอดแรกในองค์ประกอบที่เชื่อมต่ออย่างมากที่เลือกฉันคิดว่านี่เป็นปัญหาที่ยาก

6) รวมเส้นทางข้างต้นในวงจรเอเลเรียนที่จะแปลงวงจรอีริเรียนไปเป็นเส้นทาง

ทำไม - ฉันยอมรับว่าคำถามนี้น่าจะเป็นปัญหาที่ยากที่สุด (เดาไม่ได้พูดทางคณิตศาสตร์) แต่วิธีการข้างต้นทำงานได้ดีที่สุดเมื่อมีรายการยาว (1,000+) ของคำที่กระจายอย่างสม่ำเสมอ (เช่นไม่ได้ตั้งใจที่จะเป็น wc สำหรับวิธีการข้างต้น) ขอให้เราสมมติว่าหลังจากแปลงรายการที่ระบุเป็นกราฟที่กล่าวถึงข้างต้นแล้วโชคดีที่กลายเป็นกราฟ eulerian (ดูที่http://en.wikipedia.org/wiki/Eulerian_pathสำหรับเงื่อนไข) จากนั้นไม่ต้องสงสัยเลยว่าเราสามารถพูดคำตอบนั้นได้ คำถามข้างต้นคือ P และเป็นเส้นทางของ eulerian ในกราฟ (ดูhttp://www.graph-magics.com/articles/euler.phpเพื่อดูการอนุมัติที่ง่ายมากและดูสิ่งนี้เพื่อยืนยันว่ากราฟของคุณมีhttp://www.geeksforgeeks.orgเดียวและหากไม่ได้ทำความสะอาด scc ขนาดเล็กอื่นชั่วคราวเนื่องจากมีเส้นทางของ eulerian สำหรับ scc เดียว) ดังนั้นสำหรับกรณีที่ไม่ได้โชคดี (ซึ่งเกือบทุกกรณี) ฉันพยายามที่จะแปลงเป็นกรณีที่โชคดี (เช่นเงื่อนไขเส้นทาง eulerian เป็นจริง) ทำอย่างไร ฉันพยายามเพิ่มการค้นหาเชิงลึกเพื่อหาขอบที่ไม่เกี่ยวข้อง (ชุดของขอบในเส้นทางที่จ้องมองจากจุดสุดยอดที่มีค่าเริ่มต้นมากกว่าผู้เริ่มต้นและสิ้นสุดที่จุดสุดยอดด้วยการตั้งค่าที่ไม่ใหญ่กว่า) การเพิ่มการค้นหาเชิงลึกนั้นหมายถึงตอนแรกที่ฉันค้นหาชุดของขอบหนึ่งในเส้นทางทั้งหมดกว่าสองขอบในเส้นทางและอื่น ๆ มันอาจดูเป็นครั้งแรกที่การค้นหาเชิงลึกซึ่งจะใช้ O (โหนด ^ i) ดังนั้นความซับซ้อนของเวลาทั้งหมดของ O (โหนด + โหนด ^ 2 + โหนด ^ 3 + .... ) จนกระทั่งมันเป็นกรณีที่โชคดี แต่การวิเคราะห์ค่าตัดจำหน่ายจะมีความสุขมากมันเป็น O (ขอบ) เมื่อมันถูกลดขนาดผู้โชคดีพบวงจร eulerian

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


@ GlenH7 ฉันแก้ไขคำถามที่คล้ายกันใน www.hackerearth / jda เมื่อเร็ว ๆ นี้มีเครื่องหมายสัมพัทธ์ที่เกี่ยวข้องกับวิธีการแก้ปัญหาที่ดีที่สุดและฉันได้คะแนนสูงสุดด้วยการอนุมัติต่อไปนี้
vishfrnds

0

ความคิด:

ขั้นแรกสร้างสองแผนที่ (แฮช), พูด, S และ E จากตัวอักษรตัวอักษรเป็นคำ ตัวแรก, S, ตัวอักษรเริ่มต้นแผนที่คำที่สอง, E, ทำเช่นเดียวกันกับตัวอักษรลงท้าย

เช่นถ้าพจนานุกรมประกอบด้วย:

นก, จาน, สุนัข, ฮาร์บ

เรามี:

S:

a -> [ ]
b -> [ bird ]
c -> [ ]
d -> [ dish, dog ]
...
h -> [ harb ]
...

และ,

E:

a -> [ ]
b -> [ harb ]
c -> [ ]
d -> [ bird ]
...
g -> [ dog ]
h -> [ dish ]
...

จากนั้นใช้ S และ E สำหรับการค้นหาอย่างรวดเร็วสร้างฟอเรสต์ (ชุดของต้นไม้) ที่มีขนาดเท่ากับพจนานุกรมโดยมีรากที่แต่ละคำและไม่อนุญาตให้ใช้คำที่ปรากฏมากกว่าหนึ่งครั้งในต้นไม้ - แคช ความลึกของต้นไม้เมื่อคุณสร้างมัน:

bird (depth: 2)
   dish
      harb
   dog

dish (depth: 3)
   harb
      bird
         dog

dog (depth: 0)

harb (depth: 2)
   bird
      dish
      dog

ในที่สุดวนซ้ำไปตามป่าและหาต้นไม้ที่มีความลึกที่สุด

คำตอบจะอยู่ที่แกนลูกหลานของต้นไม้เหล่านั้น

เช่น,

dish / harb / bird / dog

ข้างบน.

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